@nxuss/lemma 1.42.0 → 1.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/brain-ingest.js +18 -0
- package/bin/cloud.js +228 -0
- package/bin/init.js +1 -1
- package/dist/cjs/cli/hostHooks.d.ts +6 -0
- package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
- package/dist/cjs/cli/hostHooks.js +13 -3
- package/dist/cjs/cli/hostHooks.js.map +1 -1
- package/dist/cjs/cloud/CloudBrainClient.d.ts +52 -0
- package/dist/cjs/cloud/CloudBrainClient.d.ts.map +1 -0
- package/dist/cjs/cloud/CloudBrainClient.js +161 -0
- package/dist/cjs/cloud/CloudBrainClient.js.map +1 -0
- package/dist/cjs/cloud/CloudConfig.d.ts +41 -0
- package/dist/cjs/cloud/CloudConfig.d.ts.map +1 -0
- package/dist/cjs/cloud/CloudConfig.js +133 -0
- package/dist/cjs/cloud/CloudConfig.js.map +1 -0
- package/dist/cjs/cloud/CloudEntitlement.d.ts +55 -0
- package/dist/cjs/cloud/CloudEntitlement.d.ts.map +1 -0
- package/dist/cjs/cloud/CloudEntitlement.js +174 -0
- package/dist/cjs/cloud/CloudEntitlement.js.map +1 -0
- package/dist/cjs/cloud/billing/stripeApi.d.ts +43 -0
- package/dist/cjs/cloud/billing/stripeApi.d.ts.map +1 -0
- package/dist/cjs/cloud/billing/stripeApi.js +111 -0
- package/dist/cjs/cloud/billing/stripeApi.js.map +1 -0
- package/dist/cjs/cloud/billing/stripeWebhook.d.ts +35 -0
- package/dist/cjs/cloud/billing/stripeWebhook.d.ts.map +1 -0
- package/dist/cjs/cloud/billing/stripeWebhook.js +185 -0
- package/dist/cjs/cloud/billing/stripeWebhook.js.map +1 -0
- package/dist/cjs/cloud/console/ConsoleStore.d.ts +111 -0
- package/dist/cjs/cloud/console/ConsoleStore.d.ts.map +1 -0
- package/dist/cjs/cloud/console/ConsoleStore.js +172 -0
- package/dist/cjs/cloud/console/ConsoleStore.js.map +1 -0
- package/dist/cjs/cloud/console/consoleRouter.d.ts +68 -0
- package/dist/cjs/cloud/console/consoleRouter.d.ts.map +1 -0
- package/dist/cjs/cloud/console/consoleRouter.js +263 -0
- package/dist/cjs/cloud/console/consoleRouter.js.map +1 -0
- package/dist/cjs/cloud/console/mailer.d.ts +22 -0
- package/dist/cjs/cloud/console/mailer.d.ts.map +1 -0
- package/dist/cjs/cloud/console/mailer.js +35 -0
- package/dist/cjs/cloud/console/mailer.js.map +1 -0
- package/dist/cjs/cloud/identity/PlanPolicy.d.ts +16 -1
- package/dist/cjs/cloud/identity/PlanPolicy.d.ts.map +1 -1
- package/dist/cjs/cloud/identity/PlanPolicy.js +47 -7
- package/dist/cjs/cloud/identity/PlanPolicy.js.map +1 -1
- package/dist/cjs/cloud/identity/RateLimiter.d.ts +21 -1
- package/dist/cjs/cloud/identity/RateLimiter.d.ts.map +1 -1
- package/dist/cjs/cloud/identity/RateLimiter.js +59 -2
- package/dist/cjs/cloud/identity/RateLimiter.js.map +1 -1
- package/dist/cjs/cloud/identity/TenantResolver.d.ts +4 -1
- package/dist/cjs/cloud/identity/TenantResolver.d.ts.map +1 -1
- package/dist/cjs/cloud/identity/TenantResolver.js +1 -1
- package/dist/cjs/cloud/identity/TenantResolver.js.map +1 -1
- package/dist/cjs/cloud/identity/authenticateV2.d.ts.map +1 -1
- package/dist/cjs/cloud/identity/authenticateV2.js +7 -4
- package/dist/cjs/cloud/identity/authenticateV2.js.map +1 -1
- package/dist/cjs/cloud/identity/identityStore.d.ts +85 -10
- package/dist/cjs/cloud/identity/identityStore.d.ts.map +1 -1
- package/dist/cjs/cloud/identity/identityStore.js +184 -2
- package/dist/cjs/cloud/identity/identityStore.js.map +1 -1
- package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts +16 -0
- package/dist/cjs/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
- package/dist/cjs/cloud/metering/PostgresLedgerStore.js +44 -0
- package/dist/cjs/cloud/metering/PostgresLedgerStore.js.map +1 -0
- package/dist/cjs/cloud/metering/UsageLedger.d.ts +37 -0
- package/dist/cjs/cloud/metering/UsageLedger.d.ts.map +1 -1
- package/dist/cjs/cloud/metering/UsageLedger.js +80 -17
- package/dist/cjs/cloud/metering/UsageLedger.js.map +1 -1
- package/dist/cjs/cloud/metering/index.d.ts +1 -0
- package/dist/cjs/cloud/metering/index.d.ts.map +1 -1
- package/dist/cjs/cloud/metering/index.js +1 -0
- package/dist/cjs/cloud/metering/index.js.map +1 -1
- package/dist/cjs/cloud/store/FileBrainStore.d.ts +1 -0
- package/dist/cjs/cloud/store/FileBrainStore.d.ts.map +1 -1
- package/dist/cjs/cloud/store/FileBrainStore.js +3 -0
- package/dist/cjs/cloud/store/FileBrainStore.js.map +1 -1
- package/dist/cjs/cloud/store/PostgresBrainStore.d.ts +1 -0
- package/dist/cjs/cloud/store/PostgresBrainStore.d.ts.map +1 -1
- package/dist/cjs/cloud/store/PostgresBrainStore.js +4 -0
- package/dist/cjs/cloud/store/PostgresBrainStore.js.map +1 -1
- package/dist/cjs/cloud/v2/app.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/app.js +6 -0
- package/dist/cjs/cloud/v2/app.js.map +1 -1
- package/dist/cjs/cloud/v2/inputGuard.d.ts +23 -0
- package/dist/cjs/cloud/v2/inputGuard.d.ts.map +1 -0
- package/dist/cjs/cloud/v2/inputGuard.js +71 -0
- package/dist/cjs/cloud/v2/inputGuard.js.map +1 -0
- package/dist/cjs/cloud/v2/routes/admin.d.ts +24 -0
- package/dist/cjs/cloud/v2/routes/admin.d.ts.map +1 -0
- package/dist/cjs/cloud/v2/routes/admin.js +329 -0
- package/dist/cjs/cloud/v2/routes/admin.js.map +1 -0
- package/dist/cjs/cloud/v2/routes/entitlement.d.ts +13 -0
- package/dist/cjs/cloud/v2/routes/entitlement.d.ts.map +1 -0
- package/dist/cjs/cloud/v2/routes/entitlement.js +24 -0
- package/dist/cjs/cloud/v2/routes/entitlement.js.map +1 -0
- package/dist/cjs/cloud/v2/routes/index.d.ts +14 -1
- package/dist/cjs/cloud/v2/routes/index.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/routes/index.js +36 -0
- package/dist/cjs/cloud/v2/routes/index.js.map +1 -1
- package/dist/cjs/cloud/v2/routes/memories.d.ts +21 -2
- package/dist/cjs/cloud/v2/routes/memories.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/routes/memories.js +77 -0
- package/dist/cjs/cloud/v2/routes/memories.js.map +1 -1
- package/dist/cjs/cloud/v2/routes/recall.d.ts +1 -0
- package/dist/cjs/cloud/v2/routes/recall.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/routes/recall.js +4 -0
- package/dist/cjs/cloud/v2/routes/recall.js.map +1 -1
- package/dist/cjs/cloud/v2/routes/tenant.d.ts +35 -0
- package/dist/cjs/cloud/v2/routes/tenant.d.ts.map +1 -0
- package/dist/cjs/cloud/v2/routes/tenant.js +62 -0
- package/dist/cjs/cloud/v2/routes/tenant.js.map +1 -0
- package/dist/cjs/cloud/v2/routes/usage.d.ts +1 -1
- package/dist/cjs/cloud/v2/routes/usage.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/routes/verify.d.ts +1 -0
- package/dist/cjs/cloud/v2/routes/verify.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/routes/verify.js +4 -0
- package/dist/cjs/cloud/v2/routes/verify.js.map +1 -1
- package/dist/cjs/cloud/v2/server.d.ts +9 -3
- package/dist/cjs/cloud/v2/server.d.ts.map +1 -1
- package/dist/cjs/cloud/v2/server.js +36 -2
- package/dist/cjs/cloud/v2/server.js.map +1 -1
- package/dist/cjs/cloud/v2/usageRecorder.d.ts +19 -0
- package/dist/cjs/cloud/v2/usageRecorder.d.ts.map +1 -0
- package/dist/cjs/cloud/v2/usageRecorder.js +42 -0
- package/dist/cjs/cloud/v2/usageRecorder.js.map +1 -0
- package/dist/cjs/contracts/api-v2.types.d.ts +90 -2
- package/dist/cjs/contracts/api-v2.types.d.ts.map +1 -1
- package/dist/cjs/contracts/store.d.ts +2 -0
- package/dist/cjs/contracts/store.d.ts.map +1 -1
- package/dist/cjs/mcp/index.js +3 -0
- package/dist/cjs/mcp/index.js.map +1 -1
- package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
- package/dist/cjs/mcp/tools/memory.js +104 -11
- package/dist/cjs/mcp/tools/memory.js.map +1 -1
- package/dist/cjs/mcp/tools.d.ts.map +1 -1
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/cjs/proxy/KeyManager.d.ts.map +1 -1
- package/dist/cjs/proxy/KeyManager.js +5 -0
- package/dist/cjs/proxy/KeyManager.js.map +1 -1
- package/dist/cjs/subconscious/CloudBrain.d.ts +77 -0
- package/dist/cjs/subconscious/CloudBrain.d.ts.map +1 -0
- package/dist/cjs/subconscious/CloudBrain.js +347 -0
- package/dist/cjs/subconscious/CloudBrain.js.map +1 -0
- package/dist/cjs/subconscious/ProjectIdentity.d.ts +9 -0
- package/dist/cjs/subconscious/ProjectIdentity.d.ts.map +1 -0
- package/dist/cjs/subconscious/ProjectIdentity.js +63 -0
- package/dist/cjs/subconscious/ProjectIdentity.js.map +1 -0
- package/dist/cjs/subconscious/TeamBrain.d.ts +9 -3
- package/dist/cjs/subconscious/TeamBrain.d.ts.map +1 -1
- package/dist/cjs/subconscious/TeamBrain.js +39 -5
- package/dist/cjs/subconscious/TeamBrain.js.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.d.ts +7 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.js +25 -0
- package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
- package/dist/cjs/utils/ProLicense.d.ts.map +1 -1
- package/dist/cjs/utils/ProLicense.js +11 -3
- package/dist/cjs/utils/ProLicense.js.map +1 -1
- package/dist/cjs/utils/SessionCapture.d.ts +2 -0
- package/dist/cjs/utils/SessionCapture.d.ts.map +1 -1
- package/dist/cjs/utils/SessionCapture.js +5 -0
- package/dist/cjs/utils/SessionCapture.js.map +1 -1
- package/dist/cjs/utils/StopNudge.d.ts +8 -0
- package/dist/cjs/utils/StopNudge.d.ts.map +1 -0
- package/dist/cjs/utils/StopNudge.js +93 -0
- package/dist/cjs/utils/StopNudge.js.map +1 -0
- package/dist/esm/cli/hostHooks.d.ts +6 -0
- package/dist/esm/cli/hostHooks.d.ts.map +1 -1
- package/dist/esm/cli/hostHooks.js +12 -2
- package/dist/esm/cli/hostHooks.js.map +1 -1
- package/dist/esm/cloud/CloudBrainClient.d.ts +52 -0
- package/dist/esm/cloud/CloudBrainClient.d.ts.map +1 -0
- package/dist/esm/cloud/CloudBrainClient.js +153 -0
- package/dist/esm/cloud/CloudBrainClient.js.map +1 -0
- package/dist/esm/cloud/CloudConfig.d.ts +41 -0
- package/dist/esm/cloud/CloudConfig.d.ts.map +1 -0
- package/dist/esm/cloud/CloudConfig.js +118 -0
- package/dist/esm/cloud/CloudConfig.js.map +1 -0
- package/dist/esm/cloud/CloudEntitlement.d.ts +55 -0
- package/dist/esm/cloud/CloudEntitlement.d.ts.map +1 -0
- package/dist/esm/cloud/CloudEntitlement.js +159 -0
- package/dist/esm/cloud/CloudEntitlement.js.map +1 -0
- package/dist/esm/cloud/billing/stripeApi.d.ts +43 -0
- package/dist/esm/cloud/billing/stripeApi.d.ts.map +1 -0
- package/dist/esm/cloud/billing/stripeApi.js +103 -0
- package/dist/esm/cloud/billing/stripeApi.js.map +1 -0
- package/dist/esm/cloud/billing/stripeWebhook.d.ts +35 -0
- package/dist/esm/cloud/billing/stripeWebhook.d.ts.map +1 -0
- package/dist/esm/cloud/billing/stripeWebhook.js +176 -0
- package/dist/esm/cloud/billing/stripeWebhook.js.map +1 -0
- package/dist/esm/cloud/console/ConsoleStore.d.ts +111 -0
- package/dist/esm/cloud/console/ConsoleStore.d.ts.map +1 -0
- package/dist/esm/cloud/console/ConsoleStore.js +161 -0
- package/dist/esm/cloud/console/ConsoleStore.js.map +1 -0
- package/dist/esm/cloud/console/consoleRouter.d.ts +68 -0
- package/dist/esm/cloud/console/consoleRouter.d.ts.map +1 -0
- package/dist/esm/cloud/console/consoleRouter.js +252 -0
- package/dist/esm/cloud/console/consoleRouter.js.map +1 -0
- package/dist/esm/cloud/console/mailer.d.ts +22 -0
- package/dist/esm/cloud/console/mailer.d.ts.map +1 -0
- package/dist/esm/cloud/console/mailer.js +30 -0
- package/dist/esm/cloud/console/mailer.js.map +1 -0
- package/dist/esm/cloud/identity/PlanPolicy.d.ts +16 -1
- package/dist/esm/cloud/identity/PlanPolicy.d.ts.map +1 -1
- package/dist/esm/cloud/identity/PlanPolicy.js +46 -6
- package/dist/esm/cloud/identity/PlanPolicy.js.map +1 -1
- package/dist/esm/cloud/identity/RateLimiter.d.ts +21 -1
- package/dist/esm/cloud/identity/RateLimiter.d.ts.map +1 -1
- package/dist/esm/cloud/identity/RateLimiter.js +57 -2
- package/dist/esm/cloud/identity/RateLimiter.js.map +1 -1
- package/dist/esm/cloud/identity/TenantResolver.d.ts +4 -1
- package/dist/esm/cloud/identity/TenantResolver.d.ts.map +1 -1
- package/dist/esm/cloud/identity/TenantResolver.js +1 -1
- package/dist/esm/cloud/identity/TenantResolver.js.map +1 -1
- package/dist/esm/cloud/identity/authenticateV2.d.ts.map +1 -1
- package/dist/esm/cloud/identity/authenticateV2.js +7 -4
- package/dist/esm/cloud/identity/authenticateV2.js.map +1 -1
- package/dist/esm/cloud/identity/identityStore.d.ts +85 -10
- package/dist/esm/cloud/identity/identityStore.d.ts.map +1 -1
- package/dist/esm/cloud/identity/identityStore.js +180 -1
- package/dist/esm/cloud/identity/identityStore.js.map +1 -1
- package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts +16 -0
- package/dist/esm/cloud/metering/PostgresLedgerStore.d.ts.map +1 -0
- package/dist/esm/cloud/metering/PostgresLedgerStore.js +40 -0
- package/dist/esm/cloud/metering/PostgresLedgerStore.js.map +1 -0
- package/dist/esm/cloud/metering/UsageLedger.d.ts +37 -0
- package/dist/esm/cloud/metering/UsageLedger.d.ts.map +1 -1
- package/dist/esm/cloud/metering/UsageLedger.js +78 -16
- package/dist/esm/cloud/metering/UsageLedger.js.map +1 -1
- package/dist/esm/cloud/metering/index.d.ts +1 -0
- package/dist/esm/cloud/metering/index.d.ts.map +1 -1
- package/dist/esm/cloud/metering/index.js +1 -0
- package/dist/esm/cloud/metering/index.js.map +1 -1
- package/dist/esm/cloud/store/FileBrainStore.d.ts +1 -0
- package/dist/esm/cloud/store/FileBrainStore.d.ts.map +1 -1
- package/dist/esm/cloud/store/FileBrainStore.js +3 -0
- package/dist/esm/cloud/store/FileBrainStore.js.map +1 -1
- package/dist/esm/cloud/store/PostgresBrainStore.d.ts +1 -0
- package/dist/esm/cloud/store/PostgresBrainStore.d.ts.map +1 -1
- package/dist/esm/cloud/store/PostgresBrainStore.js +4 -0
- package/dist/esm/cloud/store/PostgresBrainStore.js.map +1 -1
- package/dist/esm/cloud/v2/app.d.ts.map +1 -1
- package/dist/esm/cloud/v2/app.js +6 -0
- package/dist/esm/cloud/v2/app.js.map +1 -1
- package/dist/esm/cloud/v2/inputGuard.d.ts +23 -0
- package/dist/esm/cloud/v2/inputGuard.d.ts.map +1 -0
- package/dist/esm/cloud/v2/inputGuard.js +63 -0
- package/dist/esm/cloud/v2/inputGuard.js.map +1 -0
- package/dist/esm/cloud/v2/routes/admin.d.ts +24 -0
- package/dist/esm/cloud/v2/routes/admin.d.ts.map +1 -0
- package/dist/esm/cloud/v2/routes/admin.js +322 -0
- package/dist/esm/cloud/v2/routes/admin.js.map +1 -0
- package/dist/esm/cloud/v2/routes/entitlement.d.ts +13 -0
- package/dist/esm/cloud/v2/routes/entitlement.d.ts.map +1 -0
- package/dist/esm/cloud/v2/routes/entitlement.js +21 -0
- package/dist/esm/cloud/v2/routes/entitlement.js.map +1 -0
- package/dist/esm/cloud/v2/routes/index.d.ts +14 -1
- package/dist/esm/cloud/v2/routes/index.d.ts.map +1 -1
- package/dist/esm/cloud/v2/routes/index.js +37 -1
- package/dist/esm/cloud/v2/routes/index.js.map +1 -1
- package/dist/esm/cloud/v2/routes/memories.d.ts +21 -2
- package/dist/esm/cloud/v2/routes/memories.d.ts.map +1 -1
- package/dist/esm/cloud/v2/routes/memories.js +75 -0
- package/dist/esm/cloud/v2/routes/memories.js.map +1 -1
- package/dist/esm/cloud/v2/routes/recall.d.ts +1 -0
- package/dist/esm/cloud/v2/routes/recall.d.ts.map +1 -1
- package/dist/esm/cloud/v2/routes/recall.js +5 -1
- package/dist/esm/cloud/v2/routes/recall.js.map +1 -1
- package/dist/esm/cloud/v2/routes/tenant.d.ts +35 -0
- package/dist/esm/cloud/v2/routes/tenant.d.ts.map +1 -0
- package/dist/esm/cloud/v2/routes/tenant.js +58 -0
- package/dist/esm/cloud/v2/routes/tenant.js.map +1 -0
- package/dist/esm/cloud/v2/routes/usage.d.ts +1 -1
- package/dist/esm/cloud/v2/routes/usage.d.ts.map +1 -1
- package/dist/esm/cloud/v2/routes/verify.d.ts +1 -0
- package/dist/esm/cloud/v2/routes/verify.d.ts.map +1 -1
- package/dist/esm/cloud/v2/routes/verify.js +5 -1
- package/dist/esm/cloud/v2/routes/verify.js.map +1 -1
- package/dist/esm/cloud/v2/server.d.ts +9 -3
- package/dist/esm/cloud/v2/server.d.ts.map +1 -1
- package/dist/esm/cloud/v2/server.js +36 -3
- package/dist/esm/cloud/v2/server.js.map +1 -1
- package/dist/esm/cloud/v2/usageRecorder.d.ts +19 -0
- package/dist/esm/cloud/v2/usageRecorder.d.ts.map +1 -0
- package/dist/esm/cloud/v2/usageRecorder.js +37 -0
- package/dist/esm/cloud/v2/usageRecorder.js.map +1 -0
- package/dist/esm/contracts/api-v2.types.d.ts +90 -2
- package/dist/esm/contracts/api-v2.types.d.ts.map +1 -1
- package/dist/esm/contracts/store.d.ts +2 -0
- package/dist/esm/contracts/store.d.ts.map +1 -1
- package/dist/esm/mcp/index.js +3 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
- package/dist/esm/mcp/tools/memory.js +104 -11
- package/dist/esm/mcp/tools/memory.js.map +1 -1
- package/dist/esm/mcp/tools.d.ts.map +1 -1
- package/dist/esm/mcp/tools.js.map +1 -1
- package/dist/esm/proxy/KeyManager.d.ts.map +1 -1
- package/dist/esm/proxy/KeyManager.js +5 -0
- package/dist/esm/proxy/KeyManager.js.map +1 -1
- package/dist/esm/subconscious/CloudBrain.d.ts +77 -0
- package/dist/esm/subconscious/CloudBrain.d.ts.map +1 -0
- package/dist/esm/subconscious/CloudBrain.js +330 -0
- package/dist/esm/subconscious/CloudBrain.js.map +1 -0
- package/dist/esm/subconscious/ProjectIdentity.d.ts +9 -0
- package/dist/esm/subconscious/ProjectIdentity.d.ts.map +1 -0
- package/dist/esm/subconscious/ProjectIdentity.js +56 -0
- package/dist/esm/subconscious/ProjectIdentity.js.map +1 -0
- package/dist/esm/subconscious/TeamBrain.d.ts +9 -3
- package/dist/esm/subconscious/TeamBrain.d.ts.map +1 -1
- package/dist/esm/subconscious/TeamBrain.js +39 -7
- package/dist/esm/subconscious/TeamBrain.js.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.d.ts +7 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.js +25 -0
- package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
- package/dist/esm/utils/ProLicense.d.ts.map +1 -1
- package/dist/esm/utils/ProLicense.js +11 -3
- package/dist/esm/utils/ProLicense.js.map +1 -1
- package/dist/esm/utils/SessionCapture.d.ts +2 -0
- package/dist/esm/utils/SessionCapture.d.ts.map +1 -1
- package/dist/esm/utils/SessionCapture.js +5 -0
- package/dist/esm/utils/SessionCapture.js.map +1 -1
- package/dist/esm/utils/StopNudge.d.ts +8 -0
- package/dist/esm/utils/StopNudge.d.ts.map +1 -0
- package/dist/esm/utils/StopNudge.js +86 -0
- package/dist/esm/utils/StopNudge.js.map +1 -0
- package/lemma-proxy.cjs +5 -0
- package/package.json +2 -1
- package/sdks/crewai/dist/ts/src/client.d.ts +5 -1
- package/sdks/crewai/dist/ts/src/client.js +8 -0
- package/sdks/crewai/dist/ts/src/types.d.ts +32 -1
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loginLink = exports.AttemptLimiter = exports.SESSION_DAYS = exports.LOGIN_LINK_MINUTES = void 0;
|
|
7
|
+
exports.publicBase = publicBase;
|
|
8
|
+
exports.issueLoginLink = issueLoginLink;
|
|
9
|
+
exports.consoleRouter = consoleRouter;
|
|
10
|
+
/**
|
|
11
|
+
* Lemma Cloud console — the web app's server side, mounted at /console.
|
|
12
|
+
*
|
|
13
|
+
* GET /console/ the static app (console/index.html, app.js, styles.css)
|
|
14
|
+
* POST /console/api/login {email} asks for a sign-in link: ALWAYS 202, so it cannot tell who is a member
|
|
15
|
+
* POST /console/api/verify {token} spends the link, starts a session (HttpOnly cookie)
|
|
16
|
+
* POST /console/api/logout
|
|
17
|
+
* GET /console/api/me who you are, your tenant's plan, limits, use and (owner/admin) billing
|
|
18
|
+
* GET /console/api/usage owner/admin: requests and tokens by operation and by dev, this month
|
|
19
|
+
* GET /console/api/team owner/admin: members, keys (never a secret), seats
|
|
20
|
+
* POST /console/api/billing/portal owner/admin: Stripe billing-portal link
|
|
21
|
+
*
|
|
22
|
+
* It is a separate identity from the API keys on purpose: a key belongs to a machine and a tenant, a
|
|
23
|
+
* session belongs to a person. Sessions live in the database, so removing a member ends their access at once.
|
|
24
|
+
*
|
|
25
|
+
* Defences, each cheap: the link travels in the URL FRAGMENT (never reaches a server log or a Referer) and is
|
|
26
|
+
* posted by the page; the cookie is HttpOnly + Secure + SameSite=Lax and scoped to /console; every POST needs
|
|
27
|
+
* a custom header and a same-origin Origin (so a cross-site form cannot act); the CSP allows only our own files.
|
|
28
|
+
*/
|
|
29
|
+
const express_1 = __importDefault(require("express"));
|
|
30
|
+
const path_1 = __importDefault(require("path"));
|
|
31
|
+
const zod_1 = require("zod");
|
|
32
|
+
const errors_1 = require("../../contracts/errors");
|
|
33
|
+
const tenant_1 = require("../v2/routes/tenant");
|
|
34
|
+
const ConsoleStore_1 = require("./ConsoleStore");
|
|
35
|
+
exports.LOGIN_LINK_MINUTES = 15;
|
|
36
|
+
exports.SESSION_DAYS = 7;
|
|
37
|
+
const COOKIE = 'lemma_console';
|
|
38
|
+
const CSRF_HEADER = 'x-lemma-console';
|
|
39
|
+
/** Counts attempts per key inside a sliding window. Per instance: enough to blunt abuse, not a security boundary. */
|
|
40
|
+
class AttemptLimiter {
|
|
41
|
+
constructor(max, windowMs) {
|
|
42
|
+
this.max = max;
|
|
43
|
+
this.windowMs = windowMs;
|
|
44
|
+
this.hits = new Map();
|
|
45
|
+
}
|
|
46
|
+
allow(key, now) {
|
|
47
|
+
const recent = (this.hits.get(key) ?? []).filter((t) => now - t < this.windowMs);
|
|
48
|
+
if (recent.length >= this.max) {
|
|
49
|
+
this.hits.set(key, recent);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
recent.push(now);
|
|
53
|
+
this.hits.set(key, recent);
|
|
54
|
+
if (this.hits.size > 5000)
|
|
55
|
+
for (const [k, v] of this.hits)
|
|
56
|
+
if (!v.some((t) => now - t < this.windowMs))
|
|
57
|
+
this.hits.delete(k);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.AttemptLimiter = AttemptLimiter;
|
|
62
|
+
/** The origin the app is served from: configured, else what the proxy in front of us says. */
|
|
63
|
+
function publicBase(req, configured) {
|
|
64
|
+
if (configured)
|
|
65
|
+
return configured.replace(/\/+$/, '');
|
|
66
|
+
const proto = String(req.headers['x-forwarded-proto'] ?? req.protocol).split(',')[0].trim();
|
|
67
|
+
return `${proto}://${req.get('host')}`;
|
|
68
|
+
}
|
|
69
|
+
const loginLink = (base, token) => `${base}/console/#token=${token}`;
|
|
70
|
+
exports.loginLink = loginLink;
|
|
71
|
+
/** Issues a one-time link for an ACTIVE member; null when the email is not one. Shared with the operator route. */
|
|
72
|
+
async function issueLoginLink(store, email, now) {
|
|
73
|
+
const member = await store.findMemberByEmail(email);
|
|
74
|
+
if (!member)
|
|
75
|
+
return null;
|
|
76
|
+
const token = (0, ConsoleStore_1.newToken)();
|
|
77
|
+
const expiresAt = now + exports.LOGIN_LINK_MINUTES * 60000;
|
|
78
|
+
await store.createLoginToken({ tokenHash: (0, ConsoleStore_1.hashToken)(token), tenantId: member.tenantId, email: member.email, expiresAt });
|
|
79
|
+
return { token, email: member.email, expiresAt };
|
|
80
|
+
}
|
|
81
|
+
const LoginSchema = zod_1.z.object({ email: zod_1.z.string().trim().email().max(254) });
|
|
82
|
+
const VerifySchema = zod_1.z.object({ token: zod_1.z.string().min(20).max(200) });
|
|
83
|
+
const fail = (status, code, message) => new errors_1.LemmaApiError({ code, status, message });
|
|
84
|
+
function readCookie(req, name) {
|
|
85
|
+
for (const part of (req.headers.cookie ?? '').split(';')) {
|
|
86
|
+
const i = part.indexOf('=');
|
|
87
|
+
if (i > 0 && part.slice(0, i).trim() === name)
|
|
88
|
+
return part.slice(i + 1).trim();
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
function consoleRouter(deps) {
|
|
93
|
+
const clock = deps.now ?? Date.now;
|
|
94
|
+
const loginByIp = new AttemptLimiter(20, 60 * 60000);
|
|
95
|
+
const loginByEmail = new AttemptLimiter(5, exports.LOGIN_LINK_MINUTES * 60000);
|
|
96
|
+
const verifyByIp = new AttemptLimiter(30, 15 * 60000);
|
|
97
|
+
const r = express_1.default.Router();
|
|
98
|
+
r.use((_req, res, next) => {
|
|
99
|
+
res.set({
|
|
100
|
+
'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'",
|
|
101
|
+
'X-Content-Type-Options': 'nosniff',
|
|
102
|
+
'X-Frame-Options': 'DENY',
|
|
103
|
+
'Referrer-Policy': 'no-referrer',
|
|
104
|
+
});
|
|
105
|
+
next();
|
|
106
|
+
});
|
|
107
|
+
const api = express_1.default.Router();
|
|
108
|
+
api.use((_req, res, next) => {
|
|
109
|
+
res.set('Cache-Control', 'no-store');
|
|
110
|
+
next();
|
|
111
|
+
});
|
|
112
|
+
// Every state-changing call must come from our own page: a header a cross-site form cannot set, and an Origin that matches.
|
|
113
|
+
api.use((req, _res, next) => {
|
|
114
|
+
if (req.method === 'GET')
|
|
115
|
+
return next();
|
|
116
|
+
if (req.headers[CSRF_HEADER] !== '1')
|
|
117
|
+
return next(fail(403, 'forbidden', 'missing console header'));
|
|
118
|
+
const origin = req.headers.origin;
|
|
119
|
+
if (origin && origin !== publicBase(req, deps.publicBaseUrl))
|
|
120
|
+
return next(fail(403, 'forbidden', 'cross-origin request refused'));
|
|
121
|
+
next();
|
|
122
|
+
});
|
|
123
|
+
const wrap = (fn) => (req, res, next) => {
|
|
124
|
+
fn(req, res).catch(next);
|
|
125
|
+
};
|
|
126
|
+
const setCookie = (res, value, maxAgeSeconds) => res.append('Set-Cookie', `${COOKIE}=${value}; HttpOnly; SameSite=Lax; Path=/console; Max-Age=${maxAgeSeconds}${deps.insecureCookies ? '' : '; Secure'}`);
|
|
127
|
+
const requireSession = async (req, _res, next) => {
|
|
128
|
+
try {
|
|
129
|
+
const token = readCookie(req, COOKIE);
|
|
130
|
+
const session = token ? await deps.consoleStore.findSession((0, ConsoleStore_1.hashToken)(token), clock()) : null;
|
|
131
|
+
if (!session)
|
|
132
|
+
return next(fail(401, 'unauthenticated', 'sign in required'));
|
|
133
|
+
req.session = session;
|
|
134
|
+
next();
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
next(err);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const managerOnly = (req, _res, next) => {
|
|
141
|
+
const { role } = req.session;
|
|
142
|
+
if (role === 'owner' || role === 'admin')
|
|
143
|
+
return next();
|
|
144
|
+
next(fail(403, 'forbidden', 'only an owner or admin can see this'));
|
|
145
|
+
};
|
|
146
|
+
api.post('/login', wrap(async (req, res) => {
|
|
147
|
+
const parsed = LoginSchema.safeParse(req.body);
|
|
148
|
+
if (!parsed.success)
|
|
149
|
+
throw fail(400, 'invalid_request', 'a valid email is required');
|
|
150
|
+
const now = clock();
|
|
151
|
+
const email = (0, ConsoleStore_1.normalizeEmail)(parsed.data.email);
|
|
152
|
+
if (!loginByIp.allow(req.ip ?? 'unknown', now) || !loginByEmail.allow(email, now)) {
|
|
153
|
+
res.status(429).set('Retry-After', '900').json({ error: { code: 'rate_limited', status: 429, message: 'too many sign-in requests, try again in a few minutes' } });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const issued = await issueLoginLink(deps.consoleStore, email, now);
|
|
157
|
+
if (issued && deps.mailer) {
|
|
158
|
+
const link = (0, exports.loginLink)(publicBase(req, deps.publicBaseUrl), issued.token);
|
|
159
|
+
// Not awaited: an existing and an unknown email take the same time, and a mail outage tells no one anything.
|
|
160
|
+
deps.mailer.sendLoginLink(issued.email, link, exports.LOGIN_LINK_MINUTES).catch((err) => {
|
|
161
|
+
// eslint-disable-next-line no-console
|
|
162
|
+
console.error('[lemma:console] sign-in email failed:', err.message);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
res.status(202).json({ ok: true });
|
|
166
|
+
}));
|
|
167
|
+
api.post('/verify', wrap(async (req, res) => {
|
|
168
|
+
const parsed = VerifySchema.safeParse(req.body);
|
|
169
|
+
if (!parsed.success || !verifyByIp.allow(req.ip ?? 'unknown', clock()))
|
|
170
|
+
throw fail(401, 'unauthenticated', 'this sign-in link is not valid');
|
|
171
|
+
const now = clock();
|
|
172
|
+
const spent = await deps.consoleStore.consumeLoginToken((0, ConsoleStore_1.hashToken)(parsed.data.token), now);
|
|
173
|
+
const member = spent ? await deps.consoleStore.findMemberByEmail(spent.email) : null;
|
|
174
|
+
if (!spent || !member || member.tenantId !== spent.tenantId)
|
|
175
|
+
throw fail(401, 'unauthenticated', 'this sign-in link is not valid or has expired');
|
|
176
|
+
const session = (0, ConsoleStore_1.newToken)();
|
|
177
|
+
await deps.consoleStore.createSession({ tokenHash: (0, ConsoleStore_1.hashToken)(session), tenantId: member.tenantId, email: member.email, expiresAt: now + exports.SESSION_DAYS * 86400000 });
|
|
178
|
+
setCookie(res, session, exports.SESSION_DAYS * 86400);
|
|
179
|
+
res.json({ ok: true });
|
|
180
|
+
}));
|
|
181
|
+
api.post('/logout', wrap(async (req, res) => {
|
|
182
|
+
const token = readCookie(req, COOKIE);
|
|
183
|
+
if (token)
|
|
184
|
+
await deps.consoleStore.deleteSession((0, ConsoleStore_1.hashToken)(token));
|
|
185
|
+
setCookie(res, '', 0);
|
|
186
|
+
res.json({ ok: true });
|
|
187
|
+
}));
|
|
188
|
+
api.get('/me', requireSession, wrap(async (req, res) => {
|
|
189
|
+
const { tenantId, email, role } = req.session;
|
|
190
|
+
const tenant = await deps.identityStore.getTenant(tenantId);
|
|
191
|
+
if (!tenant)
|
|
192
|
+
throw fail(404, 'not_found', 'tenant not found');
|
|
193
|
+
const overview = await (0, tenant_1.buildTenantOverview)(deps, tenant);
|
|
194
|
+
const manager = role === 'owner' || role === 'admin';
|
|
195
|
+
// A plain member sees the plan and the limits; money (status, renewal, late payment) is for owner and admin.
|
|
196
|
+
res.json({ email, role, canManage: manager, tenant: manager ? overview : { ...overview, billing: { status: null, currentPeriodEnd: null, pastDueSince: null } } });
|
|
197
|
+
}));
|
|
198
|
+
api.get('/usage', requireSession, managerOnly, wrap(async (req, res) => {
|
|
199
|
+
const { tenantId } = req.session;
|
|
200
|
+
if (!deps.usageLedger?.computeKeyActivity)
|
|
201
|
+
throw new errors_1.LemmaApiError({ code: 'not_implemented', status: 501, message: 'usage ledger unavailable' });
|
|
202
|
+
const monthStart = new Date(clock());
|
|
203
|
+
const since = Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), 1);
|
|
204
|
+
const [usage, activity, keys] = await Promise.all([
|
|
205
|
+
deps.usageLedger.computeUsage({ tenantId, since }),
|
|
206
|
+
deps.usageLedger.computeKeyActivity({ tenantId, since }),
|
|
207
|
+
deps.identityStore.listKeys(tenantId),
|
|
208
|
+
]);
|
|
209
|
+
const names = new Map(keys.map((k) => [k.id, k]));
|
|
210
|
+
res.json({
|
|
211
|
+
since,
|
|
212
|
+
metrics: usage.metrics,
|
|
213
|
+
keys: activity.map((a) => ({
|
|
214
|
+
keyId: a.keyId,
|
|
215
|
+
name: names.get(a.keyId)?.name ?? null,
|
|
216
|
+
active: names.get(a.keyId)?.active ?? false,
|
|
217
|
+
requests: a.requests,
|
|
218
|
+
tokens: a.tokens,
|
|
219
|
+
byOperation: a.byOperation,
|
|
220
|
+
})),
|
|
221
|
+
});
|
|
222
|
+
}));
|
|
223
|
+
api.get('/team', requireSession, managerOnly, wrap(async (req, res) => {
|
|
224
|
+
const { tenantId } = req.session;
|
|
225
|
+
const tenant = await deps.identityStore.getTenant(tenantId);
|
|
226
|
+
if (!tenant)
|
|
227
|
+
throw fail(404, 'not_found', 'tenant not found');
|
|
228
|
+
const now = clock();
|
|
229
|
+
const [members, keys] = await Promise.all([deps.consoleStore.listMembers(tenantId), deps.identityStore.listKeys(tenantId)]);
|
|
230
|
+
const used = keys.filter((k) => k.active && (k.expiresAt === null || k.expiresAt > now)).length;
|
|
231
|
+
res.json({
|
|
232
|
+
seats: { used, limit: (deps.policy ? deps.policy.limitsFor(tenant.plan) : { seats: 0 }).seats },
|
|
233
|
+
members: members.map((m) => ({ email: m.email, role: m.role })),
|
|
234
|
+
// A key is shown by its label and state only: the hash and the secret never leave the database.
|
|
235
|
+
keys: keys.map((k) => ({ id: k.id, name: k.name, active: k.active, createdAt: k.createdAt, revokedAt: k.revokedAt })),
|
|
236
|
+
});
|
|
237
|
+
}));
|
|
238
|
+
api.post('/billing/portal', requireSession, managerOnly, wrap(async (req, res) => {
|
|
239
|
+
const { tenantId } = req.session;
|
|
240
|
+
const tenant = await deps.identityStore.getTenant(tenantId);
|
|
241
|
+
if (!tenant)
|
|
242
|
+
throw fail(404, 'not_found', 'tenant not found');
|
|
243
|
+
if (!deps.stripeApi || !tenant.billing.customerId) {
|
|
244
|
+
throw new errors_1.LemmaApiError({ code: 'invalid_request', status: 409, message: 'there is no subscription to manage yet' });
|
|
245
|
+
}
|
|
246
|
+
res.json({ url: (await deps.stripeApi.createPortal(tenant.billing.customerId)).url });
|
|
247
|
+
}));
|
|
248
|
+
r.use('/api', api);
|
|
249
|
+
// The static app. Unknown paths under /console fall back to the page itself (it routes on the fragment).
|
|
250
|
+
const dir = path_1.default.resolve(deps.consoleDir ?? path_1.default.join(process.cwd(), 'console'));
|
|
251
|
+
r.use(express_1.default.static(dir, { index: 'index.html', maxAge: 0, fallthrough: true }));
|
|
252
|
+
r.get('/', (_req, res) => res.sendFile(path_1.default.join(dir, 'index.html')));
|
|
253
|
+
// JSON errors for the API; the app never sees a stack or an HTML error page.
|
|
254
|
+
r.use('/api', (err, _req, res, next) => {
|
|
255
|
+
if (err instanceof errors_1.LemmaApiError) {
|
|
256
|
+
res.status(err.status).json(err.toJSON());
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
next(err);
|
|
260
|
+
});
|
|
261
|
+
return r;
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=consoleRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleRouter.js","sourceRoot":"","sources":["../../../../src/cloud/console/consoleRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lemma Cloud console — the sign-in email. Optional: without RESEND_API_KEY nothing is sent, and the
|
|
3
|
+
* operator hands the link over by hand (POST /v2/admin/tenants/:id/members/:email/login-link).
|
|
4
|
+
*
|
|
5
|
+
* The link is the only secret in the message and it is single use and short lived. It is never logged.
|
|
6
|
+
*/
|
|
7
|
+
export interface LoginMailer {
|
|
8
|
+
sendLoginLink(to: string, link: string, minutes: number): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export interface ResendConfig {
|
|
11
|
+
apiKey: string;
|
|
12
|
+
from: string;
|
|
13
|
+
fetchImpl?: typeof fetch;
|
|
14
|
+
}
|
|
15
|
+
export declare function resendMailerFromEnv(env?: NodeJS.ProcessEnv): LoginMailer | undefined;
|
|
16
|
+
export declare class ResendMailer implements LoginMailer {
|
|
17
|
+
private readonly config;
|
|
18
|
+
private readonly fetchImpl;
|
|
19
|
+
constructor(config: ResendConfig);
|
|
20
|
+
sendLoginLink(to: string, link: string, minutes: number): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=mailer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.d.ts","sourceRoot":"","sources":["../../../../src/cloud/console/mailer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,GAAG,SAAS,CAIjG;AAED,qBAAa,YAAa,YAAW,WAAW;IAElC,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBACZ,MAAM,EAAE,YAAY;IAI3C,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAiB9E"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResendMailer = void 0;
|
|
4
|
+
exports.resendMailerFromEnv = resendMailerFromEnv;
|
|
5
|
+
function resendMailerFromEnv(env = process.env) {
|
|
6
|
+
const apiKey = env.RESEND_API_KEY;
|
|
7
|
+
if (!apiKey)
|
|
8
|
+
return undefined;
|
|
9
|
+
return new ResendMailer({ apiKey, from: env.CONSOLE_MAIL_FROM || 'Lemma <hello@nxus.studio>' });
|
|
10
|
+
}
|
|
11
|
+
class ResendMailer {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.fetchImpl = config.fetchImpl ?? fetch;
|
|
15
|
+
}
|
|
16
|
+
async sendLoginLink(to, link, minutes) {
|
|
17
|
+
const res = await this.fetchImpl('https://api.resend.com/emails', {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { Authorization: `Bearer ${this.config.apiKey}`, 'Content-Type': 'application/json' },
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
from: this.config.from,
|
|
22
|
+
to: [to],
|
|
23
|
+
subject: 'Your Lemma Cloud sign-in link / Tu enlace de acceso a Lemma Cloud',
|
|
24
|
+
text: `Sign in to Lemma Cloud (valid ${minutes} minutes, works once):\n${link}\n\n` +
|
|
25
|
+
`Entra a Lemma Cloud (válido ${minutes} minutos, funciona una vez):\n${link}\n\n` +
|
|
26
|
+
`If you did not ask for this, ignore this email. / Si no lo pediste, ignora este correo.`,
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
// The status only: the response body and the request (which holds the link) stay out of any log.
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
throw new Error(`mail provider answered ${res.status}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.ResendMailer = ResendMailer;
|
|
35
|
+
//# sourceMappingURL=mailer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.js","sourceRoot":"","sources":["../../../../src/cloud/console/mailer.ts"],"names":[],"mappings":";;;AAgBA,kDAIC;AAJD,SAAgB,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,iBAAiB,IAAI,2BAA2B,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,MAAa,YAAY;IAEvB,YAA6B,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;QAC/C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAU,EAAE,IAAY,EAAE,OAAe;QAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,+BAA+B,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC9F,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;gBACtB,EAAE,EAAE,CAAC,EAAE,CAAC;gBACR,OAAO,EAAE,mEAAmE;gBAC5E,IAAI,EACF,iCAAiC,OAAO,2BAA2B,IAAI,MAAM;oBAC7E,+BAA+B,OAAO,iCAAiC,IAAI,MAAM;oBACjF,yFAAyF;aAC5F,CAAC;SACH,CAAC,CAAC;QACH,iGAAiG;QACjG,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;CACF;AAvBD,oCAuBC"}
|
|
@@ -9,7 +9,16 @@
|
|
|
9
9
|
* This module owns the plan table. The DB migration only stores tenancy; keeping
|
|
10
10
|
* a second copy of the limits in SQL would guarantee drift.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Cloud plans. `vinel` is the team tier (every seat also unlocks the local Pro tools) and `regnum`
|
|
14
|
+
* is the large-organisation tier. They used to be `pro` and `scale`; `pro` now means only the local
|
|
15
|
+
* Pro license, so the two are never confused. `internal` is not sold: it is for the maintainers' own
|
|
16
|
+
* accounts (huge but finite ceilings, because Infinity is banned), assigned only through the admin API,
|
|
17
|
+
* and the Stripe webhook never touches a tenant on it. Add a plan here and the type, the admin API validation
|
|
18
|
+
* and the SQL CHECK (a new migration) follow from this list.
|
|
19
|
+
*/
|
|
20
|
+
export declare const PLAN_IDS: readonly ["free", "vinel", "regnum", "internal"];
|
|
21
|
+
export type PlanId = (typeof PLAN_IDS)[number];
|
|
13
22
|
export interface PlanLimits {
|
|
14
23
|
/** Active AND verified memories the tenant may keep. */
|
|
15
24
|
activeMemories: number;
|
|
@@ -28,6 +37,12 @@ export declare const RATE_LIMIT_WINDOW_MS: number;
|
|
|
28
37
|
export declare const PLAN_UPGRADE_URL: Readonly<Record<PlanId, string>>;
|
|
29
38
|
/** Single source of truth for plan ceilings. Every value finite and > 0. */
|
|
30
39
|
export declare const PLAN_LIMITS: Readonly<Record<PlanId, PlanLimits>>;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a seat on the plan also unlocks the local Pro tools. A Record over PlanId, so adding a plan
|
|
42
|
+
* to PLAN_IDS without deciding this does not compile. The client never decides it: it asks the server
|
|
43
|
+
* (GET /v2/entitlement), so changing a plan here changes what every connected dev gets.
|
|
44
|
+
*/
|
|
45
|
+
export declare const PLAN_INCLUDES_PRO: Readonly<Record<PlanId, boolean>>;
|
|
31
46
|
export declare const DEFAULT_PLAN: PlanId;
|
|
32
47
|
/**
|
|
33
48
|
* The `Infinity` elimination check, exported so tests can prove it (and the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlanPolicy.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"PlanPolicy.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,kDAAmD,CAAC;AACzE,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,QAAsB,CAAC;AAExD,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK5D,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAiC3D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAK9D,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,MAAe,CAAC;AAU3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,CAY/E;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;AAE3F,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE;QACL,IAAI,EAAE,gBAAgB,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,SAAS,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,yFAAyF;QACzF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,cAAc,CAcxG;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAA6C;IAQ1F,2EAA2E;IAC3E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAInC,wEAAwE;IACxE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,GAAG,UAAU;IAiB5E,kEAAkE;IAClE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU;IAgBzD,OAAO,CAAC,WAAW;CAcpB"}
|
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PlanPolicy = exports.DEFAULT_PLAN = exports.PLAN_LIMITS = exports.PLAN_UPGRADE_URL = exports.RATE_LIMIT_WINDOW_MS = void 0;
|
|
3
|
+
exports.PlanPolicy = exports.DEFAULT_PLAN = exports.PLAN_INCLUDES_PRO = exports.PLAN_LIMITS = exports.PLAN_UPGRADE_URL = exports.RATE_LIMIT_WINDOW_MS = exports.PLAN_IDS = void 0;
|
|
4
4
|
exports.validatePlanLimits = validatePlanLimits;
|
|
5
5
|
exports.quotaErrorBody = quotaErrorBody;
|
|
6
|
+
/**
|
|
7
|
+
* Lemma API v2 — PlanPolicy (Lane D)
|
|
8
|
+
*
|
|
9
|
+
* Replaces `src/cloud/types.ts` PLAN_LIMITS. Quota is measured by ACTIVE-VERIFIED
|
|
10
|
+
* memories and by SEAT, not only by request count, and `Infinity` is gone —
|
|
11
|
+
* every plan has an explicit, positive ceiling. Exceeding a cap yields a 429
|
|
12
|
+
* with an actionable body: limit, current use, reset time and upgrade link.
|
|
13
|
+
*
|
|
14
|
+
* This module owns the plan table. The DB migration only stores tenancy; keeping
|
|
15
|
+
* a second copy of the limits in SQL would guarantee drift.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Cloud plans. `vinel` is the team tier (every seat also unlocks the local Pro tools) and `regnum`
|
|
19
|
+
* is the large-organisation tier. They used to be `pro` and `scale`; `pro` now means only the local
|
|
20
|
+
* Pro license, so the two are never confused. `internal` is not sold: it is for the maintainers' own
|
|
21
|
+
* accounts (huge but finite ceilings, because Infinity is banned), assigned only through the admin API,
|
|
22
|
+
* and the Stripe webhook never touches a tenant on it. Add a plan here and the type, the admin API validation
|
|
23
|
+
* and the SQL CHECK (a new migration) follow from this list.
|
|
24
|
+
*/
|
|
25
|
+
exports.PLAN_IDS = ['free', 'vinel', 'regnum', 'internal'];
|
|
6
26
|
exports.RATE_LIMIT_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
7
27
|
exports.PLAN_UPGRADE_URL = Object.freeze({
|
|
8
28
|
free: 'https://lemma.dev/pricing',
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
vinel: 'https://lemma.dev/pricing',
|
|
30
|
+
regnum: 'https://lemma.dev/contact',
|
|
31
|
+
internal: 'https://lemma.dev/contact',
|
|
11
32
|
});
|
|
12
33
|
/** Single source of truth for plan ceilings. Every value finite and > 0. */
|
|
13
34
|
exports.PLAN_LIMITS = Object.freeze({
|
|
@@ -19,22 +40,41 @@ exports.PLAN_LIMITS = Object.freeze({
|
|
|
19
40
|
rateLimitWindowMs: exports.RATE_LIMIT_WINDOW_MS,
|
|
20
41
|
upgradeUrl: exports.PLAN_UPGRADE_URL.free,
|
|
21
42
|
}),
|
|
22
|
-
|
|
43
|
+
vinel: Object.freeze({
|
|
23
44
|
activeMemories: 10000,
|
|
24
45
|
seats: 10,
|
|
25
46
|
dailyRequests: 5000,
|
|
26
47
|
monthlyRequests: 60000,
|
|
27
48
|
rateLimitWindowMs: exports.RATE_LIMIT_WINDOW_MS,
|
|
28
|
-
upgradeUrl: exports.PLAN_UPGRADE_URL.
|
|
49
|
+
upgradeUrl: exports.PLAN_UPGRADE_URL.vinel,
|
|
29
50
|
}),
|
|
30
|
-
|
|
51
|
+
regnum: Object.freeze({
|
|
31
52
|
activeMemories: 100000,
|
|
32
53
|
seats: 50,
|
|
33
54
|
dailyRequests: 20000,
|
|
34
55
|
monthlyRequests: 250000,
|
|
35
56
|
rateLimitWindowMs: exports.RATE_LIMIT_WINDOW_MS,
|
|
36
|
-
upgradeUrl: exports.PLAN_UPGRADE_URL.
|
|
57
|
+
upgradeUrl: exports.PLAN_UPGRADE_URL.regnum,
|
|
37
58
|
}),
|
|
59
|
+
internal: Object.freeze({
|
|
60
|
+
activeMemories: 10000000,
|
|
61
|
+
seats: 25,
|
|
62
|
+
dailyRequests: 1000000,
|
|
63
|
+
monthlyRequests: 30000000,
|
|
64
|
+
rateLimitWindowMs: exports.RATE_LIMIT_WINDOW_MS,
|
|
65
|
+
upgradeUrl: exports.PLAN_UPGRADE_URL.internal,
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Whether a seat on the plan also unlocks the local Pro tools. A Record over PlanId, so adding a plan
|
|
70
|
+
* to PLAN_IDS without deciding this does not compile. The client never decides it: it asks the server
|
|
71
|
+
* (GET /v2/entitlement), so changing a plan here changes what every connected dev gets.
|
|
72
|
+
*/
|
|
73
|
+
exports.PLAN_INCLUDES_PRO = Object.freeze({
|
|
74
|
+
free: false,
|
|
75
|
+
vinel: true,
|
|
76
|
+
regnum: true,
|
|
77
|
+
internal: true,
|
|
38
78
|
});
|
|
39
79
|
exports.DEFAULT_PLAN = 'free';
|
|
40
80
|
const NUMERIC_LIMIT_KEYS = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlanPolicy.js","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"PlanPolicy.js","sourceRoot":"","sources":["../../../../src/cloud/identity/PlanPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,13 +19,22 @@ export interface RateLimitDecision {
|
|
|
19
19
|
}
|
|
20
20
|
export interface RateLimiter {
|
|
21
21
|
consume(tenantId: string, limit: number, windowMs: number, now?: number): Promise<RateLimitDecision>;
|
|
22
|
+
/** Requests counted in the current window, WITHOUT counting this call. For reporting, never for enforcing. */
|
|
23
|
+
peek?(tenantId: string, windowMs: number, now?: number): Promise<number>;
|
|
24
|
+
/** One request against the tenant's calendar-month (UTC) allowance; resetAt is the first instant of the next month. */
|
|
25
|
+
consumeMonthly?(tenantId: string, limit: number, now?: number): Promise<RateLimitDecision>;
|
|
26
|
+
/** Requests counted this calendar month, WITHOUT counting this call. For reporting, never for enforcing. */
|
|
27
|
+
peekMonthly?(tenantId: string, now?: number): Promise<number>;
|
|
22
28
|
}
|
|
29
|
+
/** Which allowance a 429 came from. */
|
|
30
|
+
export type RateLimitWindow = 'day' | 'month';
|
|
23
31
|
/** The 429 body for rate_limited (additive to the LemmaApiError envelope). */
|
|
24
32
|
export interface RateLimitErrorBody {
|
|
25
33
|
error: {
|
|
26
34
|
code: 'rate_limited';
|
|
27
35
|
status: 429;
|
|
28
36
|
message: string;
|
|
37
|
+
window: RateLimitWindow;
|
|
29
38
|
limit: number;
|
|
30
39
|
used: number;
|
|
31
40
|
remaining: number;
|
|
@@ -34,16 +43,27 @@ export interface RateLimitErrorBody {
|
|
|
34
43
|
upgradeUrl: string;
|
|
35
44
|
};
|
|
36
45
|
}
|
|
37
|
-
export declare function rateLimitErrorBody(decision: RateLimitDecision, retryAfterSeconds: number, upgradeUrl: string): RateLimitErrorBody;
|
|
46
|
+
export declare function rateLimitErrorBody(decision: RateLimitDecision, retryAfterSeconds: number, upgradeUrl: string, window?: RateLimitWindow): RateLimitErrorBody;
|
|
47
|
+
/** Bucket id of the calendar month (UTC) that contains `now`, e.g. `m:2026-10`. Text, so it shares the daily buckets' table without clashing. */
|
|
48
|
+
export declare function monthBucket(now: number): string;
|
|
49
|
+
/** First instant (epoch ms) of the UTC month after the one containing `now`. */
|
|
50
|
+
export declare function nextMonthStart(now: number): number;
|
|
38
51
|
/** In-process fixed-window limiter. Suitable for single-instance dev and tests. */
|
|
39
52
|
export declare class InMemoryRateLimiter implements RateLimiter {
|
|
40
53
|
private readonly buckets;
|
|
41
54
|
consume(tenantId: string, limit: number, windowMs: number, now?: number): Promise<RateLimitDecision>;
|
|
55
|
+
peek(tenantId: string, windowMs: number, now?: number): Promise<number>;
|
|
56
|
+
private readonly months;
|
|
57
|
+
consumeMonthly(tenantId: string, limit: number, now?: number): Promise<RateLimitDecision>;
|
|
58
|
+
peekMonthly(tenantId: string, now?: number): Promise<number>;
|
|
42
59
|
}
|
|
43
60
|
/** Postgres-backed fixed-window limiter, atomic via a single upsert. */
|
|
44
61
|
export declare class PostgresRateLimiter implements RateLimiter {
|
|
45
62
|
private readonly pool;
|
|
46
63
|
constructor(pool: Pool);
|
|
47
64
|
consume(tenantId: string, limit: number, windowMs: number, now?: number): Promise<RateLimitDecision>;
|
|
65
|
+
peek(tenantId: string, windowMs: number, now?: number): Promise<number>;
|
|
66
|
+
consumeMonthly(tenantId: string, limit: number, now?: number): Promise<RateLimitDecision>;
|
|
67
|
+
peekMonthly(tenantId: string, now?: number): Promise<number>;
|
|
48
68
|
}
|
|
49
69
|
//# sourceMappingURL=RateLimiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../../src/cloud/identity/RateLimiter.ts"],"names":[],"mappings":"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"}
|