From 65709cec92aec953c369e43b8a311c5c83e37df1 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 20 Oct 2025 18:17:10 -1000 Subject: [PATCH] feat: init example --- package.json | 3 +- sign-as-action/nodejs/.env.example | 1 + sign-as-action/nodejs/.mocharc.json | 4 + sign-as-action/nodejs/README.md | 0 sign-as-action/nodejs/package.json | 30 +++++ sign-as-action/nodejs/project.json | 12 ++ sign-as-action/nodejs/src/index.ts | 4 + sign-as-action/nodejs/src/signAsAction.ts | 47 ++++++++ .../nodejs/src/signAsActionLitAction.ts | 11 ++ sign-as-action/nodejs/src/utils.ts | 66 ++++++++++ .../nodejs/src/verifyActionSignature.ts | 48 ++++++++ .../src/verifyActionSignatureLitAction.ts | 12 ++ sign-as-action/nodejs/test/index.spec.ts | 60 ++++++++++ sign-as-action/nodejs/tsconfig.json | 113 ++++++++++++++++++ yarn.lock | 23 ++++ 15 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 sign-as-action/nodejs/.env.example create mode 100644 sign-as-action/nodejs/.mocharc.json create mode 100644 sign-as-action/nodejs/README.md create mode 100644 sign-as-action/nodejs/package.json create mode 100644 sign-as-action/nodejs/project.json create mode 100644 sign-as-action/nodejs/src/index.ts create mode 100644 sign-as-action/nodejs/src/signAsAction.ts create mode 100644 sign-as-action/nodejs/src/signAsActionLitAction.ts create mode 100644 sign-as-action/nodejs/src/utils.ts create mode 100644 sign-as-action/nodejs/src/verifyActionSignature.ts create mode 100644 sign-as-action/nodejs/src/verifyActionSignatureLitAction.ts create mode 100644 sign-as-action/nodejs/test/index.spec.ts create mode 100644 sign-as-action/nodejs/tsconfig.json diff --git a/package.json b/package.json index 6ff79e47..82f116ed 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "wrapped-keys/nodejs", "hacker-guides/encryption/encrypt-file", "hacker-guides/encryption/encrypt-large-file", - "hacker-guides/encryption/encrypt-string" + "hacker-guides/encryption/encrypt-string", + "sign-as-action/nodejs" ], "scripts": { "install:all": "yarn workspaces focus --all", diff --git a/sign-as-action/nodejs/.env.example b/sign-as-action/nodejs/.env.example new file mode 100644 index 00000000..5cf94fb7 --- /dev/null +++ b/sign-as-action/nodejs/.env.example @@ -0,0 +1 @@ +ETHEREUM_PRIVATE_KEY= diff --git a/sign-as-action/nodejs/.mocharc.json b/sign-as-action/nodejs/.mocharc.json new file mode 100644 index 00000000..e8ecf2c6 --- /dev/null +++ b/sign-as-action/nodejs/.mocharc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json.schemastore.org/mocharc.json", + "require": "tsx" +} diff --git a/sign-as-action/nodejs/README.md b/sign-as-action/nodejs/README.md new file mode 100644 index 00000000..e69de29b diff --git a/sign-as-action/nodejs/package.json b/sign-as-action/nodejs/package.json new file mode 100644 index 00000000..ae7ddbf8 --- /dev/null +++ b/sign-as-action/nodejs/package.json @@ -0,0 +1,30 @@ +{ + "name": "sign-as-action-nodejs", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "type": "module", + "scripts": { + "test": "npx @dotenvx/dotenvx run -- mocha test/**/*.spec.ts" + }, + "dependencies": { + "@dotenvx/dotenvx": "^0.44.1", + "@lit-protocol/auth-helpers": "^7.0.4", + "@lit-protocol/constants": "^7.0.4", + "@lit-protocol/contracts-sdk": "^7.0.4", + "@lit-protocol/lit-node-client": "^7.0.4", + "ethers": "5.7.2" + }, + "devDependencies": { + "@types/chai": "^4.3.16", + "@types/chai-json-schema": "^1.4.10", + "@types/mocha": "^10.0.6", + "chai": "4.5.0", + "chai-json-schema": "^1.5.1", + "ipfs-only-hash": "^4.0.0", + "mocha": "^10.4.0", + "tsc": "^2.0.4", + "tsx": "^4.12.0", + "typescript": "^5.4.5" + } +} diff --git a/sign-as-action/nodejs/project.json b/sign-as-action/nodejs/project.json new file mode 100644 index 00000000..a3018e43 --- /dev/null +++ b/sign-as-action/nodejs/project.json @@ -0,0 +1,12 @@ +{ + "name": "sign-as-action-nodejs", + "root": "sign-as-action/nodejs", + "targets": { + "test-lit": { + "executor": "nx:run-commands", + "options": { + "command": "cd sign-as-action/nodejs && yarn && yarn test" + } + } + } +} diff --git a/sign-as-action/nodejs/src/index.ts b/sign-as-action/nodejs/src/index.ts new file mode 100644 index 00000000..37b9892a --- /dev/null +++ b/sign-as-action/nodejs/src/index.ts @@ -0,0 +1,4 @@ +export * from "./signAsAction"; +export * from "./verifyActionSignature"; +export * from './signAsActionLitAction'; +export * from './verifyActionSignatureLitAction'; \ No newline at end of file diff --git a/sign-as-action/nodejs/src/signAsAction.ts b/sign-as-action/nodejs/src/signAsAction.ts new file mode 100644 index 00000000..6c5f4312 --- /dev/null +++ b/sign-as-action/nodejs/src/signAsAction.ts @@ -0,0 +1,47 @@ +import * as ethers from "ethers"; +import { LitNodeClient } from "@lit-protocol/lit-node-client"; +import { LIT_RPC, LIT_NETWORK } from "@lit-protocol/constants"; + +import { getEnv, getSessionSigs } from "./utils"; +import { signAsActionLitAction } from "./signAsActionLitAction"; + +const ETHEREUM_PRIVATE_KEY = getEnv("ETHEREUM_PRIVATE_KEY"); + +export const signAsAction = async ({ toSign }: { toSign: Uint8Array }) => { + let litNodeClient: LitNodeClient; + + try { + const ethersSigner = new ethers.Wallet( + ETHEREUM_PRIVATE_KEY, + new ethers.providers.JsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE) + ); + + console.log("🔄 Connecting to Lit network..."); + litNodeClient = new LitNodeClient({ + litNetwork: LIT_NETWORK.DatilDev, + debug: false, + }); + await litNodeClient.connect(); + console.log("✅ Connected to Lit network"); + + const sessionSigs = await getSessionSigs({ litNodeClient, ethersSigner }); + + console.log("🔄 Executing signAsAction Lit Action..."); + const litActionSignature = await litNodeClient.executeJs({ + sessionSigs, + code: signAsActionLitAction, + jsParams: { + toSign, + sigName: "sig", + signingScheme: "EcdsaK256Sha256", + }, + }); + console.log("✅ Executed signAsAction Lit Action"); + + return litActionSignature; + } catch (error) { + console.error(error); + } finally { + litNodeClient!.disconnect(); + } +}; diff --git a/sign-as-action/nodejs/src/signAsActionLitAction.ts b/sign-as-action/nodejs/src/signAsActionLitAction.ts new file mode 100644 index 00000000..a36947a5 --- /dev/null +++ b/sign-as-action/nodejs/src/signAsActionLitAction.ts @@ -0,0 +1,11 @@ +// @ts-nocheck +const _signAsActionLitAction = async () => { + const signature = await Lit.Actions.signAsAction({ + toSign, + sigName, + signingScheme, + }); + Lit.Actions.setResponse({ response: signature }); +}; + +export const signAsActionLitAction = `(${_signAsActionLitAction.toString()})();`; diff --git a/sign-as-action/nodejs/src/utils.ts b/sign-as-action/nodejs/src/utils.ts new file mode 100644 index 00000000..79ef38c0 --- /dev/null +++ b/sign-as-action/nodejs/src/utils.ts @@ -0,0 +1,66 @@ +import * as ethers from "ethers"; +import { LitNodeClient } from "@lit-protocol/lit-node-client"; +import { LIT_ABILITY } from "@lit-protocol/constants"; +import { + createSiweMessageWithRecaps, + generateAuthSig, + LitActionResource, +} from "@lit-protocol/auth-helpers"; + +export const getEnv = (name: string): string => { + // Browser environment + if (typeof globalThis !== 'undefined' && 'window' in globalThis) { + const envMap: Record = { + 'ETHEREUM_PRIVATE_KEY': process.env.NEXT_PUBLIC_ETHEREUM_PRIVATE_KEY + }; + const env = envMap[name]; + if (env === undefined || env === "") + throw new Error( + `Browser: ${name} ENV is not defined, please define it in the .env file` + ); + return env; + } + + // Node environment + const env = process.env[name]; + if (env === undefined || env === "") + throw new Error( + `Node: ${name} ENV is not defined, please define it in the .env file` + ); + return env; +}; + +export const getSessionSigs = async ({ litNodeClient, ethersSigner }: { litNodeClient: LitNodeClient, ethersSigner: ethers.Wallet }) => { + console.log("🔄 Getting Session Signatures..."); + const sessionSigs = await litNodeClient.getSessionSigs({ + chain: "ethereum", + expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours + resourceAbilityRequests: [ + { + resource: new LitActionResource("*"), + ability: LIT_ABILITY.LitActionExecution, + }, + ], + authNeededCallback: async ({ + resourceAbilityRequests, + expiration, + uri, + }) => { + const toSign = await createSiweMessageWithRecaps({ + uri: uri!, + expiration: expiration!, + resources: resourceAbilityRequests!, + walletAddress: ethersSigner.address, + nonce: await litNodeClient.getLatestBlockhash(), + litNodeClient, + }); + + return await generateAuthSig({ + signer: ethersSigner, + toSign, + }); + }, + }); + console.log("✅ Got Session Signatures"); + return sessionSigs; +}; diff --git a/sign-as-action/nodejs/src/verifyActionSignature.ts b/sign-as-action/nodejs/src/verifyActionSignature.ts new file mode 100644 index 00000000..26087f7d --- /dev/null +++ b/sign-as-action/nodejs/src/verifyActionSignature.ts @@ -0,0 +1,48 @@ +import * as ethers from "ethers"; +import { LitNodeClient } from "@lit-protocol/lit-node-client"; +import { LIT_RPC, LIT_NETWORK } from "@lit-protocol/constants"; + +import { getEnv, getSessionSigs } from "./utils"; +import { verifyActionSignatureLitAction } from "./verifyActionSignatureLitAction"; + +const ETHEREUM_PRIVATE_KEY = getEnv("ETHEREUM_PRIVATE_KEY"); + +export const verifyActionSignature = async ({ actionIpfsCid, toSign, signOutput }: { actionIpfsCid: string, toSign: Uint8Array, signOutput: string }) => { + let litNodeClient: LitNodeClient; + + try { + const ethersSigner = new ethers.Wallet( + ETHEREUM_PRIVATE_KEY, + new ethers.providers.JsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE) + ); + + console.log("🔄 Connecting to Lit network..."); + litNodeClient = new LitNodeClient({ + litNetwork: LIT_NETWORK.DatilDev, + debug: false, + }); + await litNodeClient.connect(); + console.log("✅ Connected to Lit network"); + + const sessionSigs = await getSessionSigs({ litNodeClient, ethersSigner }); + + console.log("🔄 Executing verifyActionSignature Lit Action..."); + const response = await litNodeClient.executeJs({ + sessionSigs, + code: verifyActionSignatureLitAction, + jsParams: { + actionIpfsCid, + toSign, + signOutput, + signingScheme: "EcdsaK256Sha256", + }, + }); + console.log("✅ Executed verifyActionSignature Lit Action"); + + return response; + } catch (error) { + console.error(error); + } finally { + litNodeClient!.disconnect(); + } +}; \ No newline at end of file diff --git a/sign-as-action/nodejs/src/verifyActionSignatureLitAction.ts b/sign-as-action/nodejs/src/verifyActionSignatureLitAction.ts new file mode 100644 index 00000000..e5b09000 --- /dev/null +++ b/sign-as-action/nodejs/src/verifyActionSignatureLitAction.ts @@ -0,0 +1,12 @@ +// @ts-nocheck +const _verifyActionSignatureLitAction = async () => { + const result = await Lit.Actions.verifyActionSignature({ + signingScheme, + actionIpfsCid, + toSign, + signOutput, + }); + Lit.Actions.setResponse({ response: JSON.stringify(result) }); +}; + +export const verifyActionSignatureLitAction = `(${_verifyActionSignatureLitAction.toString()})();`; diff --git a/sign-as-action/nodejs/test/index.spec.ts b/sign-as-action/nodejs/test/index.spec.ts new file mode 100644 index 00000000..2fa65911 --- /dev/null +++ b/sign-as-action/nodejs/test/index.spec.ts @@ -0,0 +1,60 @@ +import { expect, use } from "chai"; +import chaiJsonSchema from "chai-json-schema"; +import * as ethers from "ethers"; +import IpfsHash from "ipfs-only-hash"; + +import { signAsAction, verifyActionSignature, signAsActionLitAction } from "../src"; + +use(chaiJsonSchema); + +describe("Testing signAsAction and verifyActionSignature", () => { + let litActionSignatureString: string; + + it("should sign and verify an action signature", async () => { + const signAsActionLitActionIpfsCid = await IpfsHash.of(signAsActionLitAction); + const message = new Uint8Array( + await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode("Hello world") + ) + ); + const messageHash = ethers.utils.hexlify(message); + + const responseSchema = { + type: "object", + properties: { + response: { type: "string" }, + success: { type: "boolean", const: true }, + signedData: { type: "object" }, + decryptedData: { type: "object" }, + claimData: { type: "object" }, + }, + required: ["response", "success", "signedData", "decryptedData", "claimData"], + }; + + const result = await signAsAction({ toSign: message }); + expect(result).to.be.jsonSchema(responseSchema); + + litActionSignatureString = result!.response as string; + + const litActionSignatureObject = JSON.parse(litActionSignatureString); + expect(litActionSignatureObject).to.be.jsonSchema( + { + type: "object", + properties: { + r: { type: "string", pattern: "^[a-f0-9]{64,66}$" }, + s: { type: "string", pattern: "^[a-f0-9]{64,66}$" }, + v: { type: "integer" }, + }, + required: ["r", "s", "v"], + } + ); + + const response = await verifyActionSignature({ + actionIpfsCid: signAsActionLitActionIpfsCid, + toSign: message, + signOutput: litActionSignatureString + }); + expect(response?.response).to.be.equal('true'); + }).timeout(120_000); +}); diff --git a/sign-as-action/nodejs/tsconfig.json b/sign-as-action/nodejs/tsconfig.json new file mode 100644 index 00000000..e9908bd3 --- /dev/null +++ b/sign-as-action/nodejs/tsconfig.json @@ -0,0 +1,113 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": [ + "ES2020" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "es2022" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "mocha" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock index 3f3265ec..b8e6f319 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19492,6 +19492,29 @@ __metadata: languageName: unknown linkType: soft +"sign-as-action-nodejs@workspace:sign-as-action/nodejs": + version: 0.0.0-use.local + resolution: "sign-as-action-nodejs@workspace:sign-as-action/nodejs" + dependencies: + "@dotenvx/dotenvx": "npm:^0.44.1" + "@lit-protocol/auth-helpers": "npm:^7.0.4" + "@lit-protocol/constants": "npm:^7.0.4" + "@lit-protocol/contracts-sdk": "npm:^7.0.4" + "@lit-protocol/lit-node-client": "npm:^7.0.4" + "@types/chai": "npm:^4.3.16" + "@types/chai-json-schema": "npm:^1.4.10" + "@types/mocha": "npm:^10.0.6" + chai: "npm:4.5.0" + chai-json-schema: "npm:^1.5.1" + ethers: "npm:5.7.2" + ipfs-only-hash: "npm:^4.0.0" + mocha: "npm:^10.4.0" + tsc: "npm:^2.0.4" + tsx: "npm:^4.12.0" + typescript: "npm:^5.4.5" + languageName: unknown + linkType: soft + "signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3": version: 3.0.7 resolution: "signal-exit@npm:3.0.7"