@undefineds.co/xpod 0.3.31 → 0.3.33
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/dist/api/auth/AuthContext.d.ts +3 -2
- package/dist/api/auth/AuthContext.js +2 -1
- package/dist/api/auth/AuthContext.js.map +1 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
- package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
- package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
- package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
- package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
- package/dist/api/chatkit/pod-store.d.ts +3 -0
- package/dist/api/chatkit/pod-store.js +93 -59
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +5 -6
- package/dist/api/container/business-token.d.ts +1 -1
- package/dist/api/container/business-token.js +5 -1
- package/dist/api/container/business-token.js.map +1 -1
- package/dist/api/container/common.js +14 -10
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/routes.js +16 -3
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +2 -4
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/ChatHandler.d.ts +1 -1
- package/dist/api/handlers/ChatHandler.js +1 -1
- package/dist/api/handlers/ChatHandler.js.map +1 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
- package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
- package/dist/api/handlers/PodManagementHandler.js +114 -12
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
- package/dist/api/handlers/ProvisionHandler.js +339 -32
- package/dist/api/handlers/ProvisionHandler.js.map +1 -1
- package/dist/api/handlers/QuotaHandler.js +0 -12
- package/dist/api/handlers/QuotaHandler.js.map +1 -1
- package/dist/api/handlers/index.d.ts +0 -1
- package/dist/api/handlers/index.js +0 -1
- package/dist/api/handlers/index.js.map +1 -1
- package/dist/api/matrix/PodMatrixStore.js +26 -21
- package/dist/api/matrix/PodMatrixStore.js.map +1 -1
- package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
- package/dist/api/runs/schema.d.ts +5 -7
- package/dist/api/runs/store.js +6 -4
- package/dist/api/runs/store.js.map +1 -1
- package/dist/api/runtime.js +3 -3
- package/dist/api/runtime.js.map +1 -1
- package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
- package/dist/api/tasks/schema.d.ts +17 -13
- package/dist/api/tasks/schema.js +7 -2
- package/dist/api/tasks/schema.js.map +1 -1
- package/dist/api/tasks/store.js +1 -2
- package/dist/api/tasks/store.js.map +1 -1
- package/dist/components/context.jsonld +12 -0
- package/dist/edge/EdgeNodeAgent.d.ts +1 -1
- package/dist/edge/EdgeNodeAgent.js +1 -1
- package/dist/edge/EdgeNodeAgent.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
- package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
- package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
- package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
- package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
- package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
- package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
- package/dist/http/ClusterIngressRouter.js +6 -3
- package/dist/http/ClusterIngressRouter.js.map +1 -1
- package/dist/http/ClusterWebSocketConfigurator.js +6 -2
- package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
- package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
- package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
- package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
- package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
- package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
- package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
- package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
- package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
- package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
- package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
- package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
- package/dist/http/search/SearchHttpHandler.js +2 -2
- package/dist/http/search/SearchHttpHandler.js.map +1 -1
- package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
- package/dist/identity/drizzle/AccountRepository.js +9 -113
- package/dist/identity/drizzle/AccountRepository.js.map +1 -1
- package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
- package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
- package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
- package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
- package/dist/identity/drizzle/DdnsRepository.js +13 -49
- package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
- package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
- package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
- package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
- package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
- package/dist/identity/drizzle/PodLookupRepository.js +103 -126
- package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
- package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
- package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
- package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
- package/dist/identity/drizzle/db.d.ts +2 -1
- package/dist/identity/drizzle/db.js +173 -297
- package/dist/identity/drizzle/db.js.map +1 -1
- package/dist/identity/drizzle/schema.pg.d.ts +3 -11
- package/dist/identity/drizzle/schema.pg.js +10 -45
- package/dist/identity/drizzle/schema.pg.js.map +1 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
- package/dist/identity/drizzle/schema.sqlite.js +13 -46
- package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
- package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
- package/dist/provision/ProvisionCodeCodec.js +10 -1
- package/dist/provision/ProvisionCodeCodec.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.d.ts +8 -2
- package/dist/provision/ProvisionPodCreator.js +134 -41
- package/dist/provision/ProvisionPodCreator.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.jsonld +38 -3
- package/dist/quota/DrizzleQuotaService.d.ts +0 -4
- package/dist/quota/DrizzleQuotaService.js +1 -21
- package/dist/quota/DrizzleQuotaService.js.map +1 -1
- package/dist/quota/DrizzleQuotaService.jsonld +0 -16
- package/dist/quota/NoopQuotaService.d.ts +0 -4
- package/dist/quota/NoopQuotaService.js +0 -8
- package/dist/quota/NoopQuotaService.js.map +1 -1
- package/dist/quota/NoopQuotaService.jsonld +0 -16
- package/dist/quota/QuotaService.d.ts +0 -4
- package/dist/quota/QuotaService.js.map +1 -1
- package/dist/quota/QuotaService.jsonld +0 -16
- package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
- package/dist/service/EdgeNodeSignalClient.js +0 -4
- package/dist/service/EdgeNodeSignalClient.js.map +1 -1
- package/dist/service/PodMigrationService.d.ts +2 -2
- package/dist/service/PodMigrationService.js +4 -4
- package/dist/service/PodMigrationService.js.map +1 -1
- package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
- package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
- package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
- package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
- package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
- package/dist/storage/quota/UsageRepository.d.ts +10 -32
- package/dist/storage/quota/UsageRepository.js +84 -281
- package/dist/storage/quota/UsageRepository.js.map +1 -1
- package/dist/storage/vector/VectorIndexingListener.js +2 -2
- package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
- package/dist/subdomain/SubdomainService.d.ts +1 -1
- package/dist/subdomain/SubdomainService.js +1 -1
- package/dist/subdomain/SubdomainService.js.map +1 -1
- package/dist/subdomain/SubdomainService.jsonld +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts +21 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js +85 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/exact-records.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts +10 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js +365 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/default-id-template.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js +3 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js +5 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/insert-query-builder.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts +2 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js +2 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/repository.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts +18 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js +234 -10
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/resource-reference.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts +13 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js +19 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/schema/pod-table.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts +21 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js +78 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/exact-records.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts +10 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.d.ts.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js +362 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/default-id-template.js.map +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js +5 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/insert-query-builder.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts +2 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js +1 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/repository.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts +18 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js +225 -10
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/resource-reference.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts +13 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js +19 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/schema/pod-table.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts +5 -4
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js +4 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts +5 -4
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.d.ts.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.js +20 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/index.js.map +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
- package/package.json +3 -3
- package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
- package/dist/api/handlers/ApiKeyHandler.js +0 -153
- package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
- package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
- package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
- package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProvisionHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/ProvisionHandler.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AA2BH,0DAmJC;AAuSD,oEA+BC;AAjfD,iEAAqD;AAMrD,2EAAwE;AAexE,eAAe;AACf,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEjC,SAAgB,uBAAuB,CACrC,MAAiB,EACjB,OAAgC;IAEhC,MAAM,MAAM,GAAG,IAAA,oCAAY,EAAC,kBAAkB,CAAC,CAAC;IAChD,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,IAAI,WAAW,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,uCAAkB,CAAC,OAAO,CAAC,CAAC;IAE9C;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC1D,IAAI,IAYH,CAAC;QACF,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAQ,IAAI,EAAE,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC;gBAC7C,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,KAAK,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;YACnF,MAAM,sBAAsB,GAAG,+BAA+B,CAAC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;YACjG,MAAM,eAAe,GAAG,6BAA6B,CAAC;gBACpD,UAAU;gBACV,iBAAiB;gBACjB,sBAAsB;gBACtB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,eAAe;gBAC9B,CAAC,CAAC,GAAG,eAAe,IAAI,iBAAiB,EAAE;gBAC3C,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,WAAW,GAAG,MAAM,wBAAwB,CAAC;gBACjD,UAAU;gBACV,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,eAAe;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,iBAAiB;aAClB,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,IAAI,eAAe,EAAE,CAAC;gBACjC,MAAM,UAAU,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE;oBAC7C,UAAU,EAAE,WAAW,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;oBAC/D,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,SAAS,EAAE,eAAe;iBAC3B,CAAC,CAAC;YACL,CAAC;YAED,gDAAgD;YAChD,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC;gBACjC,KAAK,EAAE,IAAI,CAAC,SAAS;gBACrB,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ;gBACR,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG;aACzC,CAAC,CAAC;YAEH,MAAM,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,MAAM,OAAO,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAEpH,MAAM,YAAY,GAA4B;gBAC5C,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,aAAa;aACd,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACb,YAAY,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACnC,CAAC;YACD,IAAI,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;gBAC3C,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC,YAAY,CAAC,WAAW,CAAC;YAClE,CAAC;YACD,IAAI,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;gBACxC,YAAY,CAAC,cAAc,GAAG,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC;YAClE,CAAC;YACD,IAAI,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;gBACxC,YAAY,CAAC,cAAc,GAAG,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC;YAClE,CAAC;YAED,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,uBAAuB,EAAE,CAAC;gBAC7C,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;YACrD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAErB,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;AAC7C,CAAC;AAOD,MAAM,uBAAwB,SAAQ,KAAK;CAAG;AAE9C,KAAK,UAAU,wBAAwB,CAAC,OAYvC;IACC,MAAM,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACX,cAAc,EACd,MAAM,EACN,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,IAAI,EACJ,WAAW,GACZ,GAAG,OAAO,CAAC;IAEZ,IAAI,CAAC,eAAe,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAwB,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE7D,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,QAAQ,CAAC,iBAAiB,CAAC;oBAC/B,SAAS,EAAE,eAAe;oBAC1B,MAAM,EAAE,iBAAiB;oBACzB,MAAM;oBACN,SAAS,EAAE,IAAI;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,uBAAuB,CAAC,oDAAoD,CAAC,CAAC;QAC1F,CAAC;QAED,OAAO;YACL,IAAI;YACJ,YAAY,EAAE,MAAM,6BAA6B,CAAC;gBAChD,UAAU;gBACV,QAAQ;gBACR,WAAW;gBACX,MAAM;gBACN,eAAe;gBACf,iBAAiB;gBACjB,SAAS;gBACT,SAAS;gBACT,WAAW;aACZ,CAAC;SACH,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,QAAQ,CAAC,iBAAiB,CAAC;gBAC/B,SAAS,EAAE,eAAe;gBAC1B,MAAM,EAAE,iBAAiB;gBACzB,MAAM;aACP,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,CAAC,cAAc,IAAI,CAAC,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,cAAc,EAAE,QAA0C,CAAC;IAC5E,MAAM,cAAc,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACzD,IAAI,cAAc,IAAI,cAAc,CAAC,SAAS,KAAK,eAAe,IAAI,cAAc,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC7G,OAAO;YACL,IAAI;YACJ,YAAY,EAAE,cAAc,CAAC,MAAM;SACpC,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC;QAC9C,SAAS,EAAE,eAAe;QAC1B,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,UAAU,CAAC,iBAAiB,CAAC,MAAM,EAAE;QACzC,aAAa,EAAE;YACb,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,WAAW,EAAE,YAAY,CAAC,WAAW;YACrC,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,SAAS,EAAE,eAAe;YAC1B,SAAS;YACT,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC;QACD,aAAa,EAAE,YAAY,CAAC,QAAQ,IAAI,SAAS;KAClD,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,6BAA6B,CAAC,OAU5C;IACC,MAAM,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACX,MAAM,EACN,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,0BAA0B,CAAC,WAAW,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,uBAAuB,CAAC,iCAAiC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,eAAe,IAAI,iBAAiB,EAAE,CAAC;IACnE,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,QAAQ,mBAAmB,CAAC;IAE1D,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,QAAQ,CAAC,iBAAiB,CAAC;gBAC/B,SAAS,EAAE,eAAe;gBAC1B,MAAM,EAAE,iBAAiB;gBACzB,MAAM;gBACN,SAAS,EAAE,WAAW;gBACtB,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;QACL,CAAC;aAAM,IACL,QAAQ,CAAC,UAAU,KAAK,OAAO;eAC5B,QAAQ,CAAC,SAAS,KAAK,WAAW;eAClC,QAAQ,CAAC,WAAW,EACvB,CAAC;YACD,MAAM,QAAQ,CAAC,cAAc,CAAC,eAAe,EAAE;gBAC7C,SAAS,EAAE,WAAW;gBACtB,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,CAAC,YAAY,CAAC;YAC7B,MAAM,EAAE,iBAAiB;YACzB,SAAS,EAAE,eAAe;YAC1B,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,WAAW;YAClB,GAAG,EAAE,EAAE;SACR,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAiB;QAC3B,QAAQ,EAAE,YAAY;QACtB,SAAS,EAAE,eAAe;QAC1B,QAAQ;QACR,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW;KACZ,CAAC;IAEF,MAAM,UAAU,CAAC,iBAAiB,CAAC,MAAM,EAAE;QACzC,aAAa,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,eAAe;YAC1B,SAAS;YACT,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACtC,MAAM,EAAE,cAAc;SACvB;QACD,aAAa,EAAE,QAAQ,IAAI,SAAS;KACrC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAa;IAC/C,MAAM,OAAO,GAAG,0BAA0B,CAAC,KAAK,CAAC,IAAI,0BAA0B,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3G,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,OAAkC,CAAC;IACjD,OAAO;QACL,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5D,QAAQ,EAAE,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAC5D,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,OAAe;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,GAAG,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,QAAwC;IACvE,MAAM,GAAG,GAAG,QAAQ,EAAE,aAAa,CAAC;IACpC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,GAA8B,CAAC;IAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAChC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAChC,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAEpF,IACE,CAAC,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,YAAY,CAAC;WAC3E,OAAO,QAAQ,KAAK,QAAQ,EAC/B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,SAAS;QACT,SAAS;QACT,MAAM,EAAE;YACN,QAAQ;YACR,SAAS,EAAE,SAAS,IAAI,OAAO;YAC/B,QAAQ;YACR,QAAQ,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAC7D,WAAW,EAAE,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;SACvE;KACF,CAAC;AACJ,CAAC;AAkBD,SAAgB,4BAA4B,CAC1C,MAAiB,EACjB,OAA+B;IAE/B,MAAM,MAAM,GAAG,IAAA,oCAAY,EAAC,wBAAwB,CAAC,CAAC;IAEtD,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;QAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE/D,MAAM,IAAI,GAA4B;YACpC,UAAU;SACX,CAAC;QAEF,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC7B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACnC,CAAC;YACD,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa;oBACxC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,4BAA4B,kBAAkB,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE;oBACnH,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC;gBAC3D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;YACnC,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAErB,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,OAAwB;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACnC,IAAI,IAAI,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,SAAS,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,QAAwB,EAAE,MAAc,EAAE,IAAa;IACvE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,+BAA+B,CAAC,KAAyB,EAAE,iBAAqC;IACvG,IAAI,CAAC,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjH,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,WAAW,EAAE,EAAE,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,iBAAiB,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,6BAA6B,CAAC,OAKtC;IACC,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC/C,OAAO,OAAO,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/G,CAAC","sourcesContent":["/**\n * Provision Handler\n *\n * Cloud 端的 SP 注册 API\n *\n * POST /provision/nodes - SP 注册(公开,无需认证)\n * 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)\n *\n * provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。\n * CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。\n *\n * GET /provision/status - Local 端 SP 状态查询(公开)\n * 返回 SP 配置状态,供 Linx 查询\n */\n\nimport type { ServerResponse, IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider, TunnelConfig } from '../../tunnel/TunnelProvider';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\nexport interface ProvisionHandlerOptions {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n /** Cloud baseUrl,用于派生 provisionCode 签名密钥 */\n baseUrl: string;\n /** 节点域名根域名,如 \"undefineds.site\" */\n baseStorageDomain?: string;\n /** provisionCode 有效期(秒),默认 24 小时 */\n provisionCodeTtl?: number;\n}\n\n/** 默认 24 小时 */\nconst DEFAULT_TTL = 24 * 60 * 60;\n\nexport function registerProvisionRoutes(\n server: ApiServer,\n options: ProvisionHandlerOptions,\n): void {\n const logger = getLoggerFor('ProvisionHandler');\n const { repository, baseUrl, baseStorageDomain } = options;\n const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;\n const codec = new ProvisionCodeCodec(baseUrl);\n\n /**\n * POST /provision/nodes\n *\n * SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)\n *\n * Request:\n * {\n * publicUrl: string,\n * nodeId?: string,\n * displayName?: string,\n * ipv4?: string,\n * serviceToken?: string,\n * domainMode?: 'managed' | 'self-managed',\n * spDomain?: string,\n * localPort?: number,\n * tunnelToken?: string\n * }\n *\n * Response 201:\n * { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }\n */\n server.post('/provision/nodes', async (request, response) => {\n let body: {\n publicUrl?: string;\n nodeId?: string;\n nodeToken?: string;\n displayName?: string;\n ipv4?: string;\n serviceToken?: string;\n localPort?: number;\n tunnelToken?: string;\n tunnelMode?: 'client';\n domainMode?: 'managed' | 'self-managed';\n spDomain?: string;\n };\n try {\n body = await readJsonBody(request) as any ?? {};\n } catch {\n sendJson(response, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!body.publicUrl) {\n sendJson(response, 400, { error: 'publicUrl is required' });\n return;\n }\n\n try {\n new URL(body.publicUrl);\n } catch {\n sendJson(response, 400, { error: 'Invalid publicUrl format' });\n return;\n }\n\n try {\n const result = await repository.registerSpNode({\n publicUrl: body.publicUrl,\n displayName: body.displayName,\n nodeId: body.nodeId,\n nodeToken: body.nodeToken,\n serviceToken: body.serviceToken,\n });\n\n const domainMode = body.domainMode === 'self-managed' ? 'self-managed' : 'managed';\n const requestedManagedDomain = normalizeRequestedManagedDomain(body.spDomain, baseStorageDomain);\n const subdomainPrefix = resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: result.nodeId,\n });\n const spDomain = subdomainPrefix\n ? `${subdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const tunnelState = await ensureManagedTunnelState({\n repository,\n nodeId: result.nodeId,\n subdomainPrefix,\n publicUrl: body.publicUrl,\n localPort: body.localPort,\n ipv4: body.ipv4,\n tunnelToken: body.tunnelToken,\n ddnsRepo: options.ddnsRepo,\n dnsProvider: options.dnsProvider,\n tunnelProvider: options.tunnelProvider,\n baseStorageDomain,\n });\n\n if (body.ipv4 || subdomainPrefix) {\n await repository.updateNodeMode(result.nodeId, {\n accessMode: tunnelState?.mode === 'tunnel' ? 'proxy' : 'direct',\n ipv4: body.ipv4,\n subdomain: subdomainPrefix,\n });\n }\n\n // 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)\n const provisionCode = codec.encode({\n spUrl: body.publicUrl,\n serviceToken: result.serviceToken,\n nodeId: result.nodeId,\n spDomain,\n exp: Math.floor(Date.now() / 1000) + ttl,\n });\n\n logger.info(`Registered SP node ${result.nodeId} at ${body.publicUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);\n\n const responseBody: Record<string, unknown> = {\n nodeId: result.nodeId,\n nodeToken: result.nodeToken,\n serviceToken: result.serviceToken,\n provisionCode,\n };\n if (spDomain) {\n responseBody.spDomain = spDomain;\n }\n if (tunnelState?.tunnelConfig?.tunnelToken) {\n responseBody.tunnelToken = tunnelState.tunnelConfig.tunnelToken;\n }\n if (tunnelState?.tunnelConfig?.provider) {\n responseBody.tunnelProvider = tunnelState.tunnelConfig.provider;\n }\n if (tunnelState?.tunnelConfig?.endpoint) {\n responseBody.tunnelEndpoint = tunnelState.tunnelConfig.endpoint;\n }\n\n sendJson(response, 201, responseBody);\n } catch (error) {\n if (error instanceof InvalidTunnelTokenError) {\n sendJson(response, 400, { error: error.message });\n return;\n }\n logger.error(`Failed to register SP node: ${error}`);\n sendJson(response, 500, { error: 'Failed to register SP node' });\n }\n }, { public: true });\n\n logger.info('Provision routes registered');\n}\n\ninterface ManagedTunnelState {\n mode: 'direct' | 'tunnel';\n tunnelConfig?: TunnelConfig;\n}\n\nclass InvalidTunnelTokenError extends Error {}\n\nasync function ensureManagedTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n nodeId: string;\n subdomainPrefix?: string;\n baseStorageDomain?: string;\n publicUrl: string;\n localPort?: number;\n ipv4?: string;\n tunnelToken?: string;\n}): Promise<ManagedTunnelState | undefined> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n ipv4,\n tunnelToken,\n } = options;\n\n if (!subdomainPrefix || !baseStorageDomain) {\n return undefined;\n }\n\n const mode: 'direct' | 'tunnel' = ipv4 ? 'direct' : 'tunnel';\n\n if (mode === 'direct') {\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: ipv4,\n });\n }\n }\n\n return { mode };\n }\n\n if (tunnelToken) {\n if (!localPort || localPort <= 0) {\n throw new InvalidTunnelTokenError('localPort is required when tunnelToken is provided');\n }\n\n return {\n mode,\n tunnelConfig: await ensureManagedTokenTunnelState({\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n }),\n };\n }\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n });\n }\n }\n\n if (!tunnelProvider || !localPort || localPort <= 0) {\n return { mode };\n }\n\n const metadataRecord = await repository.getNodeMetadata(nodeId);\n const metadata = metadataRecord?.metadata as Record<string, unknown> | null;\n const existingTunnel = readManagedTunnelConfig(metadata);\n if (existingTunnel && existingTunnel.subdomain === subdomainPrefix && existingTunnel.localPort === localPort) {\n return {\n mode,\n tunnelConfig: existingTunnel.config,\n };\n }\n\n const tunnelConfig = await tunnelProvider.setup({\n subdomain: subdomainPrefix,\n localPort,\n });\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: tunnelConfig.provider,\n tunnelId: tunnelConfig.tunnelId,\n tunnelToken: tunnelConfig.tunnelToken,\n endpoint: tunnelConfig.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n },\n publicAddress: tunnelConfig.endpoint || publicUrl,\n });\n\n return {\n mode,\n tunnelConfig,\n };\n}\n\nasync function ensureManagedTokenTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n nodeId: string;\n subdomainPrefix: string;\n baseStorageDomain: string;\n publicUrl: string;\n localPort: number;\n tunnelToken: string;\n}): Promise<TunnelConfig> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n } = options;\n\n const parsed = parseCloudflareTunnelToken(tunnelToken);\n if (!parsed?.tunnelId) {\n throw new InvalidTunnelTokenError('Invalid Cloudflare tunnel token');\n }\n\n const endpoint = `https://${subdomainPrefix}.${baseStorageDomain}`;\n const cnameTarget = `${parsed.tunnelId}.cfargotunnel.com`;\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: cnameTarget,\n recordType: 'CNAME',\n });\n } else if (\n existing.recordType !== 'CNAME'\n || existing.ipAddress !== cnameTarget\n || existing.ipv6Address\n ) {\n await ddnsRepo.updateRecordIp(subdomainPrefix, {\n ipAddress: cnameTarget,\n ipv6Address: null,\n recordType: 'CNAME',\n });\n }\n }\n\n if (dnsProvider) {\n await dnsProvider.upsertRecord({\n domain: baseStorageDomain,\n subdomain: subdomainPrefix,\n type: 'CNAME',\n value: cnameTarget,\n ttl: 60,\n });\n }\n\n const config: TunnelConfig = {\n provider: 'cloudflare',\n subdomain: subdomainPrefix,\n endpoint,\n tunnelId: parsed.tunnelId,\n tunnelToken,\n };\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: config.provider,\n tunnelId: config.tunnelId,\n tunnelToken: config.tunnelToken,\n endpoint: config.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n source: 'client-token',\n },\n publicAddress: endpoint || publicUrl,\n });\n\n return config;\n}\n\nfunction parseCloudflareTunnelToken(token: string): { accountId?: string; tunnelId?: string } | undefined {\n const decoded = decodeJsonBase64UrlSegment(token) ?? decodeJsonBase64UrlSegment(token.split('.')[0] ?? '');\n if (!decoded || typeof decoded !== 'object') {\n return undefined;\n }\n\n const value = decoded as Record<string, unknown>;\n return {\n accountId: typeof value.a === 'string' ? value.a : undefined,\n tunnelId: typeof value.t === 'string' ? value.t : undefined,\n };\n}\n\nfunction decodeJsonBase64UrlSegment(segment: string): unknown {\n if (!segment) {\n return undefined;\n }\n\n try {\n const normalized = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n const json = Buffer.from(`${normalized}${padding}`, 'base64').toString('utf8');\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction readManagedTunnelConfig(metadata: Record<string, unknown> | null): { subdomain?: string; localPort?: number; config: TunnelConfig } | undefined {\n const raw = metadata?.managedTunnel;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n const value = raw as Record<string, unknown>;\n const provider = value.provider;\n const endpoint = value.endpoint;\n const tunnelToken = value.tunnelToken;\n const tunnelId = value.tunnelId;\n const subdomain = typeof value.subdomain === 'string' ? value.subdomain : undefined;\n const localPort = typeof value.localPort === 'number' ? value.localPort : undefined;\n\n if (\n (provider !== 'cloudflare' && provider !== 'frp' && provider !== 'sakura-frp')\n || typeof endpoint !== 'string'\n ) {\n return undefined;\n }\n\n return {\n subdomain,\n localPort,\n config: {\n provider,\n subdomain: subdomain ?? 'local',\n endpoint,\n tunnelId: typeof tunnelId === 'string' ? tunnelId : undefined,\n tunnelToken: typeof tunnelToken === 'string' ? tunnelToken : undefined,\n },\n };\n}\n\n/**\n * Local 端 SP 状态查询路由\n */\nexport interface ProvisionStatusOptions {\n /** Cloud API 端点 */\n cloudUrl?: string;\n /** 节点 ID */\n nodeId?: string;\n /** SP 子域名 */\n spDomain?: string;\n /** Cloud baseUrl,用于拼 provisionUrl */\n cloudBaseUrl?: string;\n /** provisionCode(可选,由环境变量传入) */\n provisionCode?: string;\n}\n\nexport function registerProvisionStatusRoute(\n server: ApiServer,\n options: ProvisionStatusOptions,\n): void {\n const logger = getLoggerFor('ProvisionStatusHandler');\n\n server.get('/provision/status', async (_request, response) => {\n const registered = Boolean(options.nodeId && options.cloudUrl);\n\n const body: Record<string, unknown> = {\n registered,\n };\n\n if (registered) {\n body.cloudUrl = options.cloudUrl;\n body.nodeId = options.nodeId;\n if (options.spDomain) {\n body.spDomain = options.spDomain;\n }\n if (options.cloudBaseUrl) {\n const provisionUrl = options.provisionCode\n ? `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/?provisionCode=${encodeURIComponent(options.provisionCode)}`\n : `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/`;\n body.provisionUrl = provisionUrl;\n }\n }\n\n sendJson(response, 200, body);\n }, { public: true });\n\n logger.info('Provision status route registered');\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\nfunction normalizeRequestedManagedDomain(value: string | undefined, baseStorageDomain: string | undefined): string | undefined {\n if (!value || !baseStorageDomain) {\n return undefined;\n }\n\n const domain = value.trim().toLowerCase().replace(/^https?:\\/\\//u, '').replace(/\\/.*$/u, '').replace(/\\.$/u, '');\n const suffix = `.${baseStorageDomain.toLowerCase()}`;\n if (!domain.endsWith(suffix)) {\n return undefined;\n }\n\n const prefix = domain.slice(0, -suffix.length).replace(/[^a-z0-9-]/giu, '').slice(0, 63);\n if (!prefix) {\n return undefined;\n }\n\n return `${prefix}.${baseStorageDomain}`;\n}\n\nfunction resolveManagedSubdomainPrefix(options: {\n domainMode: 'managed' | 'self-managed';\n baseStorageDomain?: string;\n requestedManagedDomain?: string;\n nodeId: string;\n}): string | undefined {\n if (options.domainMode !== 'managed' || !options.baseStorageDomain) {\n return undefined;\n }\n\n if (options.requestedManagedDomain) {\n const suffix = `.${options.baseStorageDomain}`;\n return options.requestedManagedDomain.slice(0, -suffix.length);\n }\n\n return options.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || options.nodeId.split('-')[0];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ProvisionHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/ProvisionHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provision Handler\n *\n * Cloud 端的 SP 注册 API\n *\n * POST /provision/nodes - SP 注册(公开,无需认证)\n * 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)\n *\n * provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。\n * CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。\n *\n * GET /provision/status - Local 端 SP 状态查询(公开)\n * 返回 SP 配置状态,供 Linx 查询\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ServerResponse, IncomingMessage } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider, TunnelConfig } from '../../tunnel/TunnelProvider';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\nexport interface ProvisionHandlerOptions {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n /** Cloud baseUrl,用于派生 provisionCode 签名密钥 */\n baseUrl: string;\n /** 节点域名根域名,如 \"undefineds.site\" */\n baseStorageDomain?: string;\n /** provisionCode 有效期(秒),默认 24 小时 */\n provisionCodeTtl?: number;\n}\n\n/** 默认 24 小时 */\nconst DEFAULT_TTL = 24 * 60 * 60;\nconst PROVISION_STATUS_REFRESH_GRACE_SECONDS = 5 * 60;\n\nexport function registerProvisionRoutes(\n server: ApiServer,\n options: ProvisionHandlerOptions,\n): void {\n const logger = getLoggerFor('ProvisionHandler');\n const { repository, baseUrl, baseStorageDomain } = options;\n const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;\n const codec = new ProvisionCodeCodec(baseUrl);\n\n /**\n * POST /provision/nodes\n *\n * SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)\n *\n * Request:\n * {\n * publicUrl?: string,\n * nodeId?: string,\n * displayName?: string,\n * ipv4?: string,\n * serviceToken?: string,\n * domainMode?: 'managed' | 'self-managed',\n * spDomain?: string,\n * localPort?: number,\n * tunnelToken?: string\n * }\n *\n * Response 201:\n * { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }\n */\n server.post('/provision/nodes', async (request, response) => {\n let body: {\n publicUrl?: string;\n nodeId?: string;\n nodeToken?: string;\n displayName?: string;\n ipv4?: string;\n serviceToken?: string;\n localPort?: number;\n tunnelToken?: string;\n tunnelMode?: 'client';\n domainMode?: 'managed' | 'self-managed';\n spDomain?: string;\n };\n try {\n body = await readJsonBody(request) as any ?? {};\n } catch {\n sendJson(response, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n try {\n const domainMode = body.domainMode === 'self-managed' ? 'self-managed' : 'managed';\n const requestedManagedDomain = normalizeRequestedManagedDomain(body.spDomain, baseStorageDomain);\n const shouldAllocateManagedPublicUrl = !body.publicUrl && domainMode === 'managed' && Boolean(baseStorageDomain);\n const preallocatedNodeId = shouldAllocateManagedPublicUrl\n ? (body.nodeId ?? randomUUID())\n : undefined;\n const preallocatedSubdomainPrefix = preallocatedNodeId\n ? resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: preallocatedNodeId,\n })\n : undefined;\n const preallocatedSpDomain = preallocatedSubdomainPrefix\n ? `${preallocatedSubdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const effectivePublicUrl = body.publicUrl ?? derivePublicUrlFromSpDomain(preallocatedSpDomain);\n\n if (!effectivePublicUrl) {\n sendJson(response, 400, { error: 'publicUrl is required' });\n return;\n }\n\n if (preallocatedSubdomainPrefix && baseStorageDomain && options.ddnsRepo) {\n const existing = await options.ddnsRepo.getRecord(preallocatedSubdomainPrefix);\n if (existing?.nodeId && existing.nodeId !== preallocatedNodeId) {\n sendJson(response, 409, {\n error: 'spDomain already allocated',\n spDomain: preallocatedSpDomain,\n });\n return;\n }\n }\n\n try {\n new URL(effectivePublicUrl);\n } catch {\n sendJson(response, 400, { error: 'Invalid publicUrl format' });\n return;\n }\n\n const result = await repository.registerSpNode({\n publicUrl: effectivePublicUrl,\n displayName: body.displayName,\n nodeId: preallocatedNodeId ?? body.nodeId,\n nodeToken: body.nodeToken,\n serviceToken: body.serviceToken,\n });\n\n const subdomainPrefix = preallocatedSubdomainPrefix\n ?? resolveManagedSubdomainPrefix({\n domainMode,\n baseStorageDomain,\n requestedManagedDomain,\n nodeId: result.nodeId,\n });\n const spDomain = subdomainPrefix\n ? `${subdomainPrefix}.${baseStorageDomain}`\n : undefined;\n const managedPublicUrl = derivePublicUrlFromSpDomain(spDomain);\n const provisionSpUrl = body.publicUrl ?? managedPublicUrl ?? effectivePublicUrl;\n const tunnelState = await ensureManagedTunnelState({\n repository,\n nodeId: result.nodeId,\n subdomainPrefix,\n publicUrl: provisionSpUrl,\n localPort: body.localPort,\n ipv4: body.ipv4,\n tunnelToken: body.tunnelToken,\n ddnsRepo: options.ddnsRepo,\n dnsProvider: options.dnsProvider,\n tunnelProvider: options.tunnelProvider,\n baseStorageDomain,\n });\n\n if (body.ipv4 || subdomainPrefix) {\n await repository.updateNodeMode(result.nodeId, {\n accessMode: tunnelState?.mode === 'tunnel' ? 'proxy' : 'direct',\n ipv4: body.ipv4,\n subdomain: subdomainPrefix,\n });\n }\n\n // 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)\n const provisionCode = codec.encode({\n spUrl: provisionSpUrl,\n serviceToken: result.serviceToken,\n nodeId: result.nodeId,\n spDomain,\n exp: Math.floor(Date.now() / 1000) + ttl,\n });\n\n logger.info(`Registered SP node ${result.nodeId} at ${provisionSpUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);\n\n const responseBody: Record<string, unknown> = {\n nodeId: result.nodeId,\n nodeToken: result.nodeToken,\n serviceToken: result.serviceToken,\n provisionCode,\n };\n if (managedPublicUrl) {\n responseBody.publicUrl = managedPublicUrl;\n }\n if (spDomain) {\n responseBody.spDomain = spDomain;\n }\n if (tunnelState?.tunnelConfig?.tunnelToken) {\n responseBody.tunnelToken = tunnelState.tunnelConfig.tunnelToken;\n }\n if (tunnelState?.tunnelConfig?.provider) {\n responseBody.tunnelProvider = tunnelState.tunnelConfig.provider;\n }\n if (tunnelState?.tunnelConfig?.endpoint) {\n responseBody.tunnelEndpoint = tunnelState.tunnelConfig.endpoint;\n }\n\n sendJson(response, 201, responseBody);\n } catch (error) {\n if (error instanceof InvalidTunnelTokenError) {\n sendJson(response, 400, { error: error.message });\n return;\n }\n logger.error(`Failed to register SP node: ${error}`);\n sendJson(response, 500, { error: 'Failed to register SP node' });\n }\n }, { public: true });\n\n logger.info('Provision routes registered');\n}\n\ninterface ManagedTunnelState {\n mode: 'direct' | 'tunnel';\n tunnelConfig?: TunnelConfig;\n}\n\nclass InvalidTunnelTokenError extends Error {}\n\nasync function ensureManagedTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n tunnelProvider?: TunnelProvider;\n nodeId: string;\n subdomainPrefix?: string;\n baseStorageDomain?: string;\n publicUrl: string;\n localPort?: number;\n ipv4?: string;\n tunnelToken?: string;\n}): Promise<ManagedTunnelState | undefined> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n tunnelProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n ipv4,\n tunnelToken,\n } = options;\n\n if (!subdomainPrefix || !baseStorageDomain) {\n return undefined;\n }\n\n const mode: 'direct' | 'tunnel' = ipv4 ? 'direct' : 'tunnel';\n\n if (mode === 'direct') {\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: ipv4,\n });\n }\n }\n\n return { mode };\n }\n\n if (tunnelToken) {\n if (!localPort || localPort <= 0) {\n throw new InvalidTunnelTokenError('localPort is required when tunnelToken is provided');\n }\n\n return {\n mode,\n tunnelConfig: await ensureManagedTokenTunnelState({\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n }),\n };\n }\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n });\n }\n }\n\n if (!tunnelProvider || !localPort || localPort <= 0) {\n return { mode };\n }\n\n const metadataRecord = await repository.getNodeMetadata(nodeId);\n const metadata = metadataRecord?.metadata as Record<string, unknown> | null;\n const existingTunnel = readManagedTunnelConfig(metadata);\n if (existingTunnel && existingTunnel.subdomain === subdomainPrefix && existingTunnel.localPort === localPort) {\n return {\n mode,\n tunnelConfig: existingTunnel.config,\n };\n }\n\n const tunnelConfig = await tunnelProvider.setup({\n subdomain: subdomainPrefix,\n localPort,\n });\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: tunnelConfig.provider,\n tunnelId: tunnelConfig.tunnelId,\n tunnelToken: tunnelConfig.tunnelToken,\n endpoint: tunnelConfig.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n },\n });\n\n return {\n mode,\n tunnelConfig,\n };\n}\n\nasync function ensureManagedTokenTunnelState(options: {\n repository: EdgeNodeRepository;\n ddnsRepo?: DdnsRepository;\n dnsProvider?: DnsProvider;\n nodeId: string;\n subdomainPrefix: string;\n baseStorageDomain: string;\n publicUrl: string;\n localPort: number;\n tunnelToken: string;\n}): Promise<TunnelConfig> {\n const {\n repository,\n ddnsRepo,\n dnsProvider,\n nodeId,\n subdomainPrefix,\n baseStorageDomain,\n publicUrl,\n localPort,\n tunnelToken,\n } = options;\n\n const parsed = parseCloudflareTunnelToken(tunnelToken);\n if (!parsed?.tunnelId) {\n throw new InvalidTunnelTokenError('Invalid Cloudflare tunnel token');\n }\n\n const endpoint = `https://${subdomainPrefix}.${baseStorageDomain}`;\n const cnameTarget = `${parsed.tunnelId}.cfargotunnel.com`;\n\n if (ddnsRepo) {\n const existing = await ddnsRepo.getRecord(subdomainPrefix);\n if (!existing) {\n await ddnsRepo.allocateSubdomain({\n subdomain: subdomainPrefix,\n domain: baseStorageDomain,\n nodeId,\n ipAddress: cnameTarget,\n recordType: 'CNAME',\n });\n } else if (\n existing.recordType !== 'CNAME'\n || existing.ipAddress !== cnameTarget\n || existing.ipv6Address\n ) {\n await ddnsRepo.updateRecordIp(subdomainPrefix, {\n ipAddress: cnameTarget,\n ipv6Address: null,\n recordType: 'CNAME',\n });\n }\n }\n\n if (dnsProvider) {\n await dnsProvider.upsertRecord({\n domain: baseStorageDomain,\n subdomain: subdomainPrefix,\n type: 'CNAME',\n value: cnameTarget,\n ttl: 60,\n });\n }\n\n const config: TunnelConfig = {\n provider: 'cloudflare',\n subdomain: subdomainPrefix,\n endpoint,\n tunnelId: parsed.tunnelId,\n tunnelToken,\n };\n\n await repository.mergeNodeMetadata(nodeId, {\n managedTunnel: {\n provider: config.provider,\n tunnelId: config.tunnelId,\n tunnelToken: config.tunnelToken,\n endpoint: config.endpoint,\n subdomain: subdomainPrefix,\n localPort,\n configuredAt: new Date().toISOString(),\n source: 'client-token',\n },\n });\n\n return config;\n}\n\nfunction parseCloudflareTunnelToken(token: string): { accountId?: string; tunnelId?: string } | undefined {\n const decoded = decodeJsonBase64UrlSegment(token) ?? decodeJsonBase64UrlSegment(token.split('.')[0] ?? '');\n if (!decoded || typeof decoded !== 'object') {\n return undefined;\n }\n\n const value = decoded as Record<string, unknown>;\n return {\n accountId: typeof value.a === 'string' ? value.a : undefined,\n tunnelId: typeof value.t === 'string' ? value.t : undefined,\n };\n}\n\nfunction decodeJsonBase64UrlSegment(segment: string): unknown {\n if (!segment) {\n return undefined;\n }\n\n try {\n const normalized = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n const json = Buffer.from(`${normalized}${padding}`, 'base64').toString('utf8');\n return JSON.parse(json);\n } catch {\n return undefined;\n }\n}\n\nfunction readManagedTunnelConfig(metadata: Record<string, unknown> | null): { subdomain?: string; localPort?: number; config: TunnelConfig } | undefined {\n const raw = metadata?.managedTunnel;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n const value = raw as Record<string, unknown>;\n const provider = value.provider;\n const endpoint = value.endpoint;\n const tunnelToken = value.tunnelToken;\n const tunnelId = value.tunnelId;\n const subdomain = typeof value.subdomain === 'string' ? value.subdomain : undefined;\n const localPort = typeof value.localPort === 'number' ? value.localPort : undefined;\n\n if (\n (provider !== 'cloudflare' && provider !== 'frp' && provider !== 'sakura-frp')\n || typeof endpoint !== 'string'\n ) {\n return undefined;\n }\n\n return {\n subdomain,\n localPort,\n config: {\n provider,\n subdomain: subdomain ?? 'local',\n endpoint,\n tunnelId: typeof tunnelId === 'string' ? tunnelId : undefined,\n tunnelToken: typeof tunnelToken === 'string' ? tunnelToken : undefined,\n },\n };\n}\n\n/**\n * Local 端 SP 状态查询路由\n */\nexport interface ProvisionStatusOptions {\n /** Cloud API 端点 */\n cloudUrl?: string;\n /** 节点 ID */\n nodeId?: string;\n /** 节点 Token */\n nodeToken?: string;\n /** SP service token,刷新 provisionCode 时回传给 Cloud */\n serviceToken?: string;\n /** 当前 SP canonical public URL */\n publicUrl?: string;\n /** SP 子域名 */\n spDomain?: string;\n /** 本地端口,供 Cloud 管理 tunnel 元数据 */\n localPort?: number;\n /** tunnel token,供 Cloud 维护托管域名连通性 */\n tunnelToken?: string;\n /** Cloud baseUrl,用于拼 provisionUrl */\n cloudBaseUrl?: string;\n /** provisionCode(可选,由环境变量传入) */\n provisionCode?: string;\n /** Persist refreshed local-only setup state to the single local setup file. */\n persistState?: (state: ProvisionStatusStateUpdate) => Promise<void> | void;\n /** 测试/调试注入 */\n fetchImpl?: typeof fetch;\n now?: () => number;\n refreshGraceSeconds?: number;\n}\n\nexport interface ProvisionStatusStateUpdate {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n provisionCode: string;\n publicUrl?: string;\n spDomain?: string;\n cloudUrl?: string;\n cloudBaseUrl?: string;\n}\n\nexport function registerProvisionStatusRoute(\n server: ApiServer,\n options: ProvisionStatusOptions,\n): void {\n const logger = getLoggerFor('ProvisionStatusHandler');\n const fetchImpl = options.fetchImpl ?? fetch;\n const now = options.now ?? (() => Date.now());\n const refreshGraceSeconds = options.refreshGraceSeconds ?? PROVISION_STATUS_REFRESH_GRACE_SECONDS;\n const state: ProvisionStatusState = {\n provisionCode: options.provisionCode,\n nodeId: options.nodeId,\n nodeToken: options.nodeToken,\n serviceToken: options.serviceToken,\n publicUrl: normalizeUrl(options.publicUrl),\n spDomain: options.spDomain,\n };\n let refreshPromise: Promise<void> | undefined;\n\n server.get('/provision/status', async (_request, response) => {\n const registered = Boolean(options.nodeId && options.cloudUrl);\n\n const body: Record<string, unknown> = {\n registered,\n };\n\n if (registered) {\n const canRefresh = canRefreshProvisionStatus(options, state);\n const currentNow = now();\n const fresh = isProvisionCodeFresh(state.provisionCode, currentNow, refreshGraceSeconds);\n const codeState = inspectProvisionCodeExpiration(state.provisionCode);\n if (!canRefresh && codeState.kind !== 'missing' && !isProvisionCodeUsable(state.provisionCode, currentNow)) {\n sendJson(response, 503, {\n registered: true,\n error: 'provision_refresh_unavailable',\n message: 'Local provision state is expired and cannot be refreshed. Please restart Local or try again.',\n });\n return;\n }\n\n if (canRefresh && !fresh) {\n let didRefresh = false;\n refreshPromise ??= refreshProvisionStatus({\n options,\n state,\n fetchImpl,\n logger,\n }).finally(() => {\n refreshPromise = undefined;\n });\n try {\n await refreshPromise;\n didRefresh = true;\n } catch (error) {\n logger.warn(`Failed to refresh provisionCode for ${state.nodeId}: ${error}`);\n if (!isProvisionCodeUsable(state.provisionCode, now())) {\n sendJson(response, 503, {\n registered: true,\n error: 'provision_refresh_failed',\n message: 'Local provision state could not be refreshed. Please restart Local or try again.',\n });\n return;\n }\n }\n if (didRefresh) {\n await persistProvisionStatusState(options, state, logger);\n }\n }\n\n body.cloudUrl = options.cloudUrl;\n body.nodeId = state.nodeId ?? options.nodeId;\n if (state.spDomain) {\n body.spDomain = state.spDomain;\n }\n if (state.publicUrl) {\n body.publicUrl = state.publicUrl;\n }\n if (state.provisionCode) {\n body.provisionCode = state.provisionCode;\n }\n if (options.cloudBaseUrl) {\n const provisionUrl = state.provisionCode\n ? `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`\n : `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/`;\n body.provisionUrl = provisionUrl;\n }\n }\n\n sendJson(response, 200, body);\n }, { public: true });\n\n logger.info('Provision status route registered');\n}\n\nexport function createLocalSetupProvisionStateWriter(\n setupPath: string | undefined,\n providerId: string | undefined,\n): ProvisionStatusOptions['persistState'] | undefined {\n if (!setupPath?.trim() || !providerId?.trim()) {\n return undefined;\n }\n\n const targetPath = path.resolve(setupPath);\n const targetProviderId = providerId.trim();\n return async (state): Promise<void> => {\n upsertLocalSetupFile(targetPath, targetProviderId, state);\n };\n}\n\nasync function persistProvisionStatusState(\n options: ProvisionStatusOptions,\n state: ProvisionStatusState,\n logger: ReturnType<typeof getLoggerFor>,\n): Promise<void> {\n if (!options.persistState || !state.nodeId || !state.nodeToken || !state.serviceToken || !state.provisionCode) {\n return;\n }\n\n try {\n await options.persistState({\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n provisionCode: state.provisionCode,\n publicUrl: state.publicUrl,\n spDomain: state.spDomain,\n cloudUrl: options.cloudUrl,\n cloudBaseUrl: options.cloudBaseUrl,\n });\n } catch (error) {\n logger.warn(`Failed to persist refreshed local provision state: ${error}`);\n }\n}\n\nfunction upsertLocalSetupFile(\n filePath: string,\n providerId: string,\n state: ProvisionStatusStateUpdate,\n): void {\n const existing = readJsonObjectFile(filePath);\n const previous = readJsonObject(existing[providerId]);\n const cloudIdentityUrl = normalizeUrl(state.cloudBaseUrl);\n const cloudApiUrl = normalizeUrl(state.cloudUrl);\n const provisionUrl = cloudIdentityUrl\n ? `${cloudIdentityUrl.replace(/\\/+$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`\n : readString(previous.provisionUrl);\n\n existing[providerId] = {\n ...previous,\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n provisionCode: state.provisionCode,\n publicUrl: normalizeUrl(state.publicUrl),\n spDomain: readString(state.spDomain),\n provisionUrl,\n cloudIdentityUrl,\n cloudApiUrl,\n registeredAt: typeof previous.registeredAt === 'number' && Number.isFinite(previous.registeredAt)\n ? previous.registeredAt\n : Date.now(),\n };\n\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, `${JSON.stringify(existing, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // Some filesystems do not support chmod; the local runtime can still proceed.\n }\n}\n\nfunction readJsonObjectFile(filePath: string): Record<string, unknown> {\n try {\n if (!fs.existsSync(filePath)) {\n return {};\n }\n\n return readJsonObject(JSON.parse(fs.readFileSync(filePath, 'utf8')));\n } catch {\n return {};\n }\n}\n\nfunction readJsonObject(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nfunction readString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\ninterface ProvisionStatusState {\n provisionCode?: string;\n nodeId?: string;\n nodeToken?: string;\n serviceToken?: string;\n publicUrl?: string;\n spDomain?: string;\n}\n\ninterface ProvisionNodeRefreshResponse {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n provisionCode: string;\n publicUrl?: string;\n spDomain?: string;\n}\n\nfunction canRefreshProvisionStatus(options: ProvisionStatusOptions, state: ProvisionStatusState): boolean {\n return Boolean(\n options.cloudUrl\n && state.nodeId\n && state.nodeToken\n && state.serviceToken\n && state.publicUrl,\n );\n}\n\nasync function refreshProvisionStatus(options: {\n options: ProvisionStatusOptions;\n state: ProvisionStatusState;\n fetchImpl: typeof fetch;\n logger: ReturnType<typeof getLoggerFor>;\n}): Promise<void> {\n const { options: statusOptions, state, fetchImpl, logger } = options;\n const endpoint = new URL('/provision/nodes', ensureTrailingSlash(statusOptions.cloudUrl!)).toString();\n const requestBody: Record<string, unknown> = {\n publicUrl: state.publicUrl,\n nodeId: state.nodeId,\n nodeToken: state.nodeToken,\n serviceToken: state.serviceToken,\n domainMode: state.spDomain ? 'managed' : 'self-managed',\n spDomain: state.spDomain,\n };\n\n if (statusOptions.localPort && statusOptions.localPort > 0) {\n requestBody.localPort = statusOptions.localPort;\n }\n if (statusOptions.tunnelToken) {\n requestBody.tunnelToken = statusOptions.tunnelToken;\n requestBody.tunnelMode = 'client';\n }\n\n const result = await fetchImpl(endpoint, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!result.ok) {\n const detail = await result.text().catch(() => '');\n throw new Error(detail || `HTTP ${result.status}`);\n }\n\n const payload = await result.json().catch(() => undefined) as Partial<ProvisionNodeRefreshResponse> | undefined;\n if (\n !payload\n || typeof payload.nodeId !== 'string'\n || typeof payload.nodeToken !== 'string'\n || typeof payload.serviceToken !== 'string'\n || typeof payload.provisionCode !== 'string'\n ) {\n throw new Error('Cloud returned an incomplete provision refresh response.');\n }\n\n state.nodeId = payload.nodeId;\n state.nodeToken = payload.nodeToken;\n state.serviceToken = payload.serviceToken;\n state.provisionCode = payload.provisionCode;\n state.publicUrl = normalizeUrl(payload.publicUrl) ?? state.publicUrl;\n state.spDomain = typeof payload.spDomain === 'string' ? payload.spDomain : state.spDomain;\n\n process.env.XPOD_NODE_ID = state.nodeId;\n process.env.XPOD_NODE_TOKEN = state.nodeToken;\n process.env.XPOD_SERVICE_TOKEN = state.serviceToken;\n process.env.XPOD_PROVISION_CODE = state.provisionCode;\n if (statusOptions.cloudBaseUrl) {\n process.env.XPOD_PROVISION_URL = `${statusOptions.cloudBaseUrl.replace(/\\/$/u, '')}/.account/?provisionCode=${encodeURIComponent(state.provisionCode)}`;\n }\n if (state.spDomain) {\n process.env.XPOD_SP_DOMAIN = state.spDomain;\n }\n\n logger.info(`Refreshed provisionCode for ${state.nodeId}`);\n}\n\nfunction isProvisionCodeFresh(code: string | undefined, nowMs: number, graceSeconds: number): boolean {\n const state = inspectProvisionCodeExpiration(code);\n return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000) + graceSeconds;\n}\n\nfunction isProvisionCodeUsable(code: string | undefined, nowMs: number): boolean {\n const state = inspectProvisionCodeExpiration(code);\n if (state.kind === 'legacy') {\n return true;\n }\n return state.kind === 'self-contained' && state.expiresAt > Math.floor(nowMs / 1000);\n}\n\nfunction inspectProvisionCodeExpiration(code: string | undefined): { kind: 'missing' | 'legacy' | 'invalid' } | { kind: 'self-contained'; expiresAt: number } {\n if (!code) {\n return { kind: 'missing' };\n }\n const dotIndex = code.indexOf('.');\n if (dotIndex <= 0) {\n return { kind: 'legacy' };\n }\n\n try {\n const payload = JSON.parse(Buffer.from(code.slice(0, dotIndex), 'base64url').toString('utf8')) as { exp?: unknown };\n return typeof payload.exp === 'number' && Number.isFinite(payload.exp)\n ? { kind: 'self-contained', expiresAt: payload.exp }\n : { kind: 'invalid' };\n } catch {\n return { kind: 'invalid' };\n }\n}\n\nfunction ensureTrailingSlash(value: string): string {\n return value.endsWith('/') ? value : `${value}/`;\n}\n\nfunction normalizeUrl(value: string | undefined): string | undefined {\n if (!value?.trim()) {\n return undefined;\n }\n\n try {\n return new URL(value.trim()).toString().replace(/\\/+$/u, '') + '/';\n } catch {\n return value.trim().replace(/\\/+$/u, '') + '/';\n }\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\nfunction derivePublicUrlFromSpDomain(spDomain: string | undefined): string | undefined {\n return spDomain ? `https://${spDomain}/` : undefined;\n}\n\nfunction normalizeRequestedManagedDomain(value: string | undefined, baseStorageDomain: string | undefined): string | undefined {\n if (!value || !baseStorageDomain) {\n return undefined;\n }\n\n const domain = value.trim().toLowerCase().replace(/^https?:\\/\\//u, '').replace(/\\/.*$/u, '').replace(/\\.$/u, '');\n const suffix = `.${baseStorageDomain.toLowerCase()}`;\n if (!domain.endsWith(suffix)) {\n return undefined;\n }\n\n const prefix = domain.slice(0, -suffix.length).replace(/[^a-z0-9-]/giu, '').slice(0, 63);\n if (!prefix) {\n return undefined;\n }\n\n return `${prefix}.${baseStorageDomain}`;\n}\n\nfunction resolveManagedSubdomainPrefix(options: {\n domainMode: 'managed' | 'self-managed';\n baseStorageDomain?: string;\n requestedManagedDomain?: string;\n nodeId: string;\n}): string | undefined {\n if (options.domainMode !== 'managed' || !options.baseStorageDomain) {\n return undefined;\n }\n\n if (options.requestedManagedDomain) {\n const suffix = `.${options.baseStorageDomain}`;\n return options.requestedManagedDomain.slice(0, -suffix.length);\n }\n\n return options.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || options.nodeId.split('-')[0];\n}\n"]}
|
|
@@ -226,18 +226,6 @@ function extractQuotaFields(payload) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
|
-
// Backward compat: support legacy 'quotaLimit' field
|
|
230
|
-
if (!hasField && Object.prototype.hasOwnProperty.call(payload, 'quotaLimit')) {
|
|
231
|
-
const value = payload.quotaLimit;
|
|
232
|
-
if (value === null) {
|
|
233
|
-
result.storageLimitBytes = null;
|
|
234
|
-
hasField = true;
|
|
235
|
-
}
|
|
236
|
-
else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {
|
|
237
|
-
result.storageLimitBytes = value;
|
|
238
|
-
hasField = true;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
229
|
return hasField ? result : undefined;
|
|
242
230
|
}
|
|
243
231
|
function hasCustomQuota(usage) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuotaHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/QuotaHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport type { ApiServer } from '../ApiServer';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport type { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { hasScope } from '../auth/AuthContext';\n\nexport interface QuotaHandlerOptions {\n quotaService: QuotaService;\n usageRepo: UsageRepository;\n}\n\n/**\n * Handler for quota management API\n *\n * Supports four resource types: storage, bandwidth, compute, token.\n * Requires ServiceAuthContext with 'quota:write' scope for mutations.\n *\n * GET /v1/quota/accounts/:accountId - Get account quota + usage\n * PUT /v1/quota/accounts/:accountId - Set account quota\n * DELETE /v1/quota/accounts/:accountId - Clear account quota (revert to defaults)\n * GET /v1/quota/pods/:podId - Get pod quota + usage\n * PUT /v1/quota/pods/:podId - Set pod quota\n * DELETE /v1/quota/pods/:podId - Clear pod quota\n */\nexport function registerQuotaRoutes(server: ApiServer, options: QuotaHandlerOptions): void {\n const logger = getLoggerFor('QuotaHandler');\n const { quotaService, usageRepo } = options;\n\n // GET /v1/quota/accounts/:accountId\n server.get('/v1/quota/accounts/:accountId', async (request, response, params) => {\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n const quota = await quotaService.getAccountQuota(accountId);\n const usage = await usageRepo.getAccountUsage(accountId);\n\n sendJson(response, 200, {\n accountId,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/accounts/:accountId\n server.put('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field (storageLimitBytes, bandwidthLimitBps, computeLimitSeconds, tokenLimitMonthly)' });\n return;\n }\n\n try {\n await quotaService.setAccountQuota(accountId, partial);\n const latest = await quotaService.getAccountQuota(accountId);\n\n logger.info(`Set account ${accountId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n accountId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/accounts/:accountId\n server.delete('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n await quotaService.clearAccountQuota(accountId);\n\n logger.info(`Cleared account ${accountId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n accountId,\n });\n } catch (error) {\n logger.error(`Failed to clear account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n\n // GET /v1/quota/pods/:podId\n server.get('/v1/quota/pods/:podId', async (request, response, params) => {\n const podId = decodeURIComponent(params.podId);\n\n try {\n const quota = await quotaService.getPodQuota(podId);\n const usage = await usageRepo.getPodUsage(podId);\n\n sendJson(response, 200, {\n podId,\n accountId: usage?.accountId ?? null,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/pods/:podId\n server.put('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field' });\n return;\n }\n\n try {\n await quotaService.setPodQuota(podId, partial);\n const latest = await quotaService.getPodQuota(podId);\n\n logger.info(`Set pod ${podId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n podId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/pods/:podId\n server.delete('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n\n try {\n await quotaService.clearPodQuota(podId);\n\n logger.info(`Cleared pod ${podId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n podId,\n });\n } catch (error) {\n logger.error(`Failed to clear pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n}\n\n/**\n * Check if the request has the required scope. Sends 403 if not.\n */\nfunction requireScope(request: AuthenticatedRequest, response: ServerResponse, scope: string): boolean {\n if (!request.auth) {\n sendJson(response, 401, { error: 'Authentication required' });\n return false;\n }\n // Service tokens need explicit scope; Solid users with admin role can also access\n if (request.auth.type === 'service') {\n if (!hasScope(request.auth, scope)) {\n sendJson(response, 403, { error: `Missing required scope: ${scope}` });\n return false;\n }\n return true;\n }\n // Allow Solid auth (for admin users) - actual admin check can be added later\n if (request.auth.type === 'solid') {\n return true;\n }\n sendJson(response, 403, { error: 'Insufficient permissions' });\n return false;\n}\n\nconst QUOTA_FIELDS = ['storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly'] as const;\n\nfunction extractQuotaFields(payload: Record<string, unknown>): Record<string, number | null> | undefined {\n const result: Record<string, number | null> = {};\n let hasField = false;\n\n for (const field of QUOTA_FIELDS) {\n if (Object.prototype.hasOwnProperty.call(payload, field)) {\n const value = payload[field];\n if (value === null) {\n result[field] = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result[field] = value;\n hasField = true;\n } else {\n return undefined; // Invalid value\n }\n }\n }\n\n // Backward compat: support legacy 'quotaLimit' field\n if (!hasField && Object.prototype.hasOwnProperty.call(payload, 'quotaLimit')) {\n const value = payload.quotaLimit;\n if (value === null) {\n result.storageLimitBytes = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result.storageLimitBytes = value;\n hasField = true;\n }\n }\n\n return hasField ? result : undefined;\n}\n\nfunction hasCustomQuota(usage: { storageLimitBytes?: number | null; bandwidthLimitBps?: number | null; computeLimitSeconds?: number | null; tokenLimitMonthly?: number | null } | undefined): boolean {\n if (!usage) {\n return false;\n }\n return typeof usage.storageLimitBytes === 'number'\n || typeof usage.bandwidthLimitBps === 'number'\n || typeof usage.computeLimitSeconds === 'number'\n || typeof usage.tokenLimitMonthly === 'number';\n}\n\nasync function readJsonBody(request: AuthenticatedRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"QuotaHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/QuotaHandler.ts"],"names":[],"mappings":";;AA0BA,kDA8LC;AAvND,iEAAqD;AAKrD,qDAA+C;AAO/C;;;;;;;;;;;;GAYG;AACH,SAAgB,mBAAmB,CAAC,MAAiB,EAAE,OAA4B;IACjF,MAAM,MAAM,GAAG,IAAA,oCAAY,EAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE5C,oCAAoC;IACpC,MAAM,CAAC,GAAG,CAAC,+BAA+B,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QAC9E,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YAEzD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,SAAS;gBACT,KAAK,EAAE;oBACL,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;oBAC1C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;oBAC1C,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;oBAC9C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;iBAC3C;gBACD,KAAK,EAAE;oBACL,YAAY,EAAE,KAAK,EAAE,YAAY,IAAI,CAAC;oBACtC,YAAY,EAAE,KAAK,EAAE,YAAY,IAAI,CAAC;oBACtC,WAAW,EAAE,KAAK,EAAE,WAAW,IAAI,CAAC;oBACpC,cAAc,EAAE,KAAK,EAAE,cAAc,IAAI,CAAC;oBAC1C,UAAU,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC;oBAClC,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;iBAC1F;gBACD,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;aACrD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;YACtD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,oCAAoC;IACpC,MAAM,CAAC,GAAG,CAAC,+BAA+B,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QAC9E,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAA+B,CAAC;QAChD,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,2HAA2H,EAAE,CAAC,CAAC;YAChK,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YAE7D,MAAM,CAAC,IAAI,CAAC,eAAe,SAAS,WAAW,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAE1E,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,MAAM,EAAE,SAAS;gBACjB,SAAS;gBACT,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;YACtD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,uCAAuC;IACvC,MAAM,CAAC,MAAM,CAAC,+BAA+B,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QACjF,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAEhD,MAAM,CAAC,IAAI,CAAC,mBAAmB,SAAS,QAAQ,CAAC,CAAC;YAElD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,MAAM,EAAE,SAAS;gBACjB,SAAS;aACV,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAC;YACxD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,4BAA4B;IAC5B,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QACtE,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEjD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,KAAK;gBACL,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,IAAI;gBACnC,KAAK,EAAE;oBACL,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;oBAC1C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;oBAC1C,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;oBAC9C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;iBAC3C;gBACD,KAAK,EAAE;oBACL,YAAY,EAAE,KAAK,EAAE,YAAY,IAAI,CAAC;oBACtC,YAAY,EAAE,KAAK,EAAE,YAAY,IAAI,CAAC;oBACtC,WAAW,EAAE,KAAK,EAAE,WAAW,IAAI,CAAC;oBACpC,cAAc,EAAE,KAAK,EAAE,cAAc,IAAI,CAAC;oBAC1C,UAAU,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC;oBAClC,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;iBAC1F;gBACD,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;aACrD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;YAClD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,4BAA4B;IAC5B,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QACtE,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAA+B,CAAC;QAChD,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAErD,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAElE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,MAAM,EAAE,SAAS;gBACjB,KAAK;gBACL,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;YAClD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,CAAC,MAAM,CAAC,uBAAuB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QACzE,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAExC,MAAM,CAAC,IAAI,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;YAE1C,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACtB,MAAM,EAAE,SAAS;gBACjB,KAAK;aACN,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,8BAA8B,KAAK,EAAE,CAAC,CAAC;YACpD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,OAA6B,EAAE,QAAwB,EAAE,KAAa;IAC1F,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,kFAAkF;IAClF,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,CAAC,IAAA,sBAAQ,EAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACnC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,2BAA2B,KAAK,EAAE,EAAE,CAAC,CAAC;YACvE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,6EAA6E;IAC7E,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAC/D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,CAAU,CAAC;AAErH,SAAS,kBAAkB,CAAC,OAAgC;IAC1D,MAAM,MAAM,GAAkC,EAAE,CAAC;IACjD,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;gBACrB,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC7E,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;gBACtB,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,OAAO,SAAS,CAAC,CAAC,gBAAgB;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACvC,CAAC;AAED,SAAS,cAAc,CAAC,KAAmK;IACzL,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,OAAO,KAAK,CAAC,iBAAiB,KAAK,QAAQ;WAC7C,OAAO,KAAK,CAAC,iBAAiB,KAAK,QAAQ;WAC3C,OAAO,KAAK,CAAC,mBAAmB,KAAK,QAAQ;WAC7C,OAAO,KAAK,CAAC,iBAAiB,KAAK,QAAQ,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,OAA6B;IACvD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACnC,IAAI,IAAI,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,SAAS,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,SAAS,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,QAAwB,EAAE,MAAc,EAAE,IAAa;IACvE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport type { ApiServer } from '../ApiServer';\nimport type { QuotaService } from '../../quota/QuotaService';\nimport type { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { hasScope } from '../auth/AuthContext';\n\nexport interface QuotaHandlerOptions {\n quotaService: QuotaService;\n usageRepo: UsageRepository;\n}\n\n/**\n * Handler for quota management API\n *\n * Supports four resource types: storage, bandwidth, compute, token.\n * Requires ServiceAuthContext with 'quota:write' scope for mutations.\n *\n * GET /v1/quota/accounts/:accountId - Get account quota + usage\n * PUT /v1/quota/accounts/:accountId - Set account quota\n * DELETE /v1/quota/accounts/:accountId - Clear account quota (revert to defaults)\n * GET /v1/quota/pods/:podId - Get pod quota + usage\n * PUT /v1/quota/pods/:podId - Set pod quota\n * DELETE /v1/quota/pods/:podId - Clear pod quota\n */\nexport function registerQuotaRoutes(server: ApiServer, options: QuotaHandlerOptions): void {\n const logger = getLoggerFor('QuotaHandler');\n const { quotaService, usageRepo } = options;\n\n // GET /v1/quota/accounts/:accountId\n server.get('/v1/quota/accounts/:accountId', async (request, response, params) => {\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n const quota = await quotaService.getAccountQuota(accountId);\n const usage = await usageRepo.getAccountUsage(accountId);\n\n sendJson(response, 200, {\n accountId,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/accounts/:accountId\n server.put('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field (storageLimitBytes, bandwidthLimitBps, computeLimitSeconds, tokenLimitMonthly)' });\n return;\n }\n\n try {\n await quotaService.setAccountQuota(accountId, partial);\n const latest = await quotaService.getAccountQuota(accountId);\n\n logger.info(`Set account ${accountId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n accountId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/accounts/:accountId\n server.delete('/v1/quota/accounts/:accountId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const accountId = decodeURIComponent(params.accountId);\n\n try {\n await quotaService.clearAccountQuota(accountId);\n\n logger.info(`Cleared account ${accountId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n accountId,\n });\n } catch (error) {\n logger.error(`Failed to clear account quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n\n // GET /v1/quota/pods/:podId\n server.get('/v1/quota/pods/:podId', async (request, response, params) => {\n const podId = decodeURIComponent(params.podId);\n\n try {\n const quota = await quotaService.getPodQuota(podId);\n const usage = await usageRepo.getPodUsage(podId);\n\n sendJson(response, 200, {\n podId,\n accountId: usage?.accountId ?? null,\n quota: {\n storageLimitBytes: quota.storageLimitBytes,\n bandwidthLimitBps: quota.bandwidthLimitBps,\n computeLimitSeconds: quota.computeLimitSeconds,\n tokenLimitMonthly: quota.tokenLimitMonthly,\n },\n usage: {\n storageBytes: usage?.storageBytes ?? 0,\n ingressBytes: usage?.ingressBytes ?? 0,\n egressBytes: usage?.egressBytes ?? 0,\n computeSeconds: usage?.computeSeconds ?? 0,\n tokensUsed: usage?.tokensUsed ?? 0,\n periodStart: usage?.periodStart ? new Date(usage.periodStart * 1000).toISOString() : null,\n },\n source: hasCustomQuota(usage) ? 'custom' : 'default',\n });\n } catch (error) {\n logger.error(`Failed to get pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to get quota' });\n }\n });\n\n // PUT /v1/quota/pods/:podId\n server.put('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const partial = extractQuotaFields(payload);\n if (!partial) {\n sendJson(response, 400, { error: 'Body must include at least one quota field' });\n return;\n }\n\n try {\n await quotaService.setPodQuota(podId, partial);\n const latest = await quotaService.getPodQuota(podId);\n\n logger.info(`Set pod ${podId} quota: ${JSON.stringify(partial)}`);\n\n sendJson(response, 200, {\n status: 'updated',\n podId,\n quota: latest,\n });\n } catch (error) {\n logger.error(`Failed to set pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to set quota' });\n }\n });\n\n // DELETE /v1/quota/pods/:podId\n server.delete('/v1/quota/pods/:podId', async (request, response, params) => {\n if (!requireScope(request, response, 'quota:write')) {\n return;\n }\n\n const podId = decodeURIComponent(params.podId);\n\n try {\n await quotaService.clearPodQuota(podId);\n\n logger.info(`Cleared pod ${podId} quota`);\n\n sendJson(response, 200, {\n status: 'cleared',\n podId,\n });\n } catch (error) {\n logger.error(`Failed to clear pod quota: ${error}`);\n sendJson(response, 500, { error: 'Failed to clear quota' });\n }\n });\n}\n\n/**\n * Check if the request has the required scope. Sends 403 if not.\n */\nfunction requireScope(request: AuthenticatedRequest, response: ServerResponse, scope: string): boolean {\n if (!request.auth) {\n sendJson(response, 401, { error: 'Authentication required' });\n return false;\n }\n // Service tokens need explicit scope; Solid users with admin role can also access\n if (request.auth.type === 'service') {\n if (!hasScope(request.auth, scope)) {\n sendJson(response, 403, { error: `Missing required scope: ${scope}` });\n return false;\n }\n return true;\n }\n // Allow Solid auth (for admin users) - actual admin check can be added later\n if (request.auth.type === 'solid') {\n return true;\n }\n sendJson(response, 403, { error: 'Insufficient permissions' });\n return false;\n}\n\nconst QUOTA_FIELDS = ['storageLimitBytes', 'bandwidthLimitBps', 'computeLimitSeconds', 'tokenLimitMonthly'] as const;\n\nfunction extractQuotaFields(payload: Record<string, unknown>): Record<string, number | null> | undefined {\n const result: Record<string, number | null> = {};\n let hasField = false;\n\n for (const field of QUOTA_FIELDS) {\n if (Object.prototype.hasOwnProperty.call(payload, field)) {\n const value = payload[field];\n if (value === null) {\n result[field] = null;\n hasField = true;\n } else if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n result[field] = value;\n hasField = true;\n } else {\n return undefined; // Invalid value\n }\n }\n }\n\n return hasField ? result : undefined;\n}\n\nfunction hasCustomQuota(usage: { storageLimitBytes?: number | null; bandwidthLimitBps?: number | null; computeLimitSeconds?: number | null; tokenLimitMonthly?: number | null } | undefined): boolean {\n if (!usage) {\n return false;\n }\n return typeof usage.storageLimitBytes === 'number'\n || typeof usage.bandwidthLimitBps === 'number'\n || typeof usage.computeLimitSeconds === 'number'\n || typeof usage.tokenLimitMonthly === 'number';\n}\n\nasync function readJsonBody(request: AuthenticatedRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
|
|
@@ -5,7 +5,6 @@ export * from './ChatHandler';
|
|
|
5
5
|
export * from './VectorHandler';
|
|
6
6
|
export * from './VectorStoreHandler';
|
|
7
7
|
export * from './VectorStoreWebhookHandler';
|
|
8
|
-
export * from './ApiKeyHandler';
|
|
9
8
|
export * from './SubdomainHandler';
|
|
10
9
|
export * from './SubdomainClientHandler';
|
|
11
10
|
export * from './ChatKitHandler';
|
|
@@ -21,7 +21,6 @@ __exportStar(require("./ChatHandler"), exports);
|
|
|
21
21
|
__exportStar(require("./VectorHandler"), exports);
|
|
22
22
|
__exportStar(require("./VectorStoreHandler"), exports);
|
|
23
23
|
__exportStar(require("./VectorStoreWebhookHandler"), exports);
|
|
24
|
-
__exportStar(require("./ApiKeyHandler"), exports);
|
|
25
24
|
__exportStar(require("./SubdomainHandler"), exports);
|
|
26
25
|
__exportStar(require("./SubdomainClientHandler"), exports);
|
|
27
26
|
__exportStar(require("./ChatKitHandler"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/handlers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,iDAA+B;AAC/B,gDAA8B;AAC9B,gDAA8B;AAC9B,kDAAgC;AAChC,uDAAqC;AACrC,8DAA4C;AAC5C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/handlers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,iDAA+B;AAC/B,gDAA8B;AAC9B,gDAA8B;AAC9B,kDAAgC;AAChC,uDAAqC;AACrC,8DAA4C;AAC5C,qDAAmC;AACnC,2DAAyC;AACzC,mDAAiC;AACjC,kDAAgC;AAChC,+CAA6B;AAC7B,qDAAmC;AACnC,yDAAuC","sourcesContent":["export * from './EdgeNodeSignalHandler';\nexport * from './QuotaHandler';\nexport * from './NodeHandler';\nexport * from './ChatHandler';\nexport * from './VectorHandler';\nexport * from './VectorStoreHandler';\nexport * from './VectorStoreWebhookHandler';\nexport * from './SubdomainHandler';\nexport * from './SubdomainClientHandler';\nexport * from './ChatKitHandler';\nexport * from './MatrixHandler';\nexport * from './RunHandler';\nexport * from './ProvisionHandler';\nexport * from './PodManagementHandler';\n"]}
|
|
@@ -45,12 +45,16 @@ class PodMatrixStore {
|
|
|
45
45
|
});
|
|
46
46
|
await db.insert(models_1.threadResource).values({
|
|
47
47
|
id: threadId,
|
|
48
|
-
commandKind: 'chat',
|
|
49
|
-
surfaceId: this.surfaceIdFromRoomId(roomId),
|
|
50
48
|
chat: chatId,
|
|
51
49
|
title: input.name ?? roomId,
|
|
52
50
|
status: 'active',
|
|
53
|
-
metadata: {
|
|
51
|
+
metadata: {
|
|
52
|
+
protocol: 'matrix',
|
|
53
|
+
roomId,
|
|
54
|
+
commandKind: 'chat',
|
|
55
|
+
surface_id: this.surfaceIdFromRoomId(roomId),
|
|
56
|
+
chat_id: this.surfaceIdFromRoomId(roomId),
|
|
57
|
+
},
|
|
54
58
|
createdAt: new Date(now).toISOString(),
|
|
55
59
|
updatedAt: new Date(now).toISOString(),
|
|
56
60
|
});
|
|
@@ -119,7 +123,7 @@ class PodMatrixStore {
|
|
|
119
123
|
async sendEvent(roomId, eventType, txnId, content, context) {
|
|
120
124
|
const db = await this.getDb(context);
|
|
121
125
|
await this.ensureRoomExists(db, roomId);
|
|
122
|
-
const existing = await this.findEventByTxnId(db, roomId, txnId);
|
|
126
|
+
const existing = await this.findEventByTxnId(db, roomId, txnId, context);
|
|
123
127
|
if (existing) {
|
|
124
128
|
return existing;
|
|
125
129
|
}
|
|
@@ -141,7 +145,7 @@ class PodMatrixStore {
|
|
|
141
145
|
const limit = options.limit && options.limit > 0 ? options.limit : 50;
|
|
142
146
|
const join = {};
|
|
143
147
|
for (const room of rooms) {
|
|
144
|
-
const events = await this.listEvents(db, room.roomId, {
|
|
148
|
+
const events = await this.listEvents(db, room.roomId, context, {
|
|
145
149
|
sinceTs,
|
|
146
150
|
limit,
|
|
147
151
|
});
|
|
@@ -166,7 +170,7 @@ class PodMatrixStore {
|
|
|
166
170
|
const limit = options.limit && options.limit > 0 ? options.limit : 50;
|
|
167
171
|
const fromTs = this.parseSyncToken(options.from);
|
|
168
172
|
const forward = options.dir === 'f';
|
|
169
|
-
const events = await this.listEvents(db, roomId, {
|
|
173
|
+
const events = await this.listEvents(db, roomId, context, {
|
|
170
174
|
sinceTs: forward && fromTs > 0 ? fromTs : undefined,
|
|
171
175
|
beforeOrAtTs: !forward && fromTs > 0 ? fromTs : undefined,
|
|
172
176
|
limit,
|
|
@@ -181,7 +185,7 @@ class PodMatrixStore {
|
|
|
181
185
|
}
|
|
182
186
|
async getEvent(roomId, eventId, context) {
|
|
183
187
|
const db = await this.getDb(context);
|
|
184
|
-
const event = await this.findEventById(db, roomId, eventId);
|
|
188
|
+
const event = await this.findEventById(db, roomId, eventId, context);
|
|
185
189
|
if (!event) {
|
|
186
190
|
throw new Error(`Matrix event not found: ${eventId}`);
|
|
187
191
|
}
|
|
@@ -189,7 +193,7 @@ class PodMatrixStore {
|
|
|
189
193
|
}
|
|
190
194
|
async getState(roomId, eventType, stateKey, context) {
|
|
191
195
|
const db = await this.getDb(context);
|
|
192
|
-
const event = await this.findLatestStateEvent(db, roomId, eventType, stateKey);
|
|
196
|
+
const event = await this.findLatestStateEvent(db, roomId, eventType, stateKey, context);
|
|
193
197
|
if (!event) {
|
|
194
198
|
throw new Error(`Matrix state not found: ${eventType}/${stateKey}`);
|
|
195
199
|
}
|
|
@@ -229,7 +233,7 @@ class PodMatrixStore {
|
|
|
229
233
|
}
|
|
230
234
|
async appendEvent(db, input, context) {
|
|
231
235
|
const eventId = this.generateEventId(context);
|
|
232
|
-
const depth = await this.nextEventDepth(db, input.roomId);
|
|
236
|
+
const depth = await this.nextEventDepth(db, input.roomId, context);
|
|
233
237
|
const originIso = new Date(input.originServerTs).toISOString();
|
|
234
238
|
const record = {
|
|
235
239
|
eventId,
|
|
@@ -246,8 +250,6 @@ class PodMatrixStore {
|
|
|
246
250
|
};
|
|
247
251
|
await db.insert(models_1.messageResource).values({
|
|
248
252
|
id: this.messageResourceIdFromEvent(input.roomId, eventId, input.originServerTs),
|
|
249
|
-
commandKind: 'chat',
|
|
250
|
-
surfaceId: this.surfaceIdFromRoomId(input.roomId),
|
|
251
253
|
chat: this.chatResourceIdFromRoomId(input.roomId),
|
|
252
254
|
thread: this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(input.roomId), context),
|
|
253
255
|
maker: context.userId,
|
|
@@ -266,6 +268,9 @@ class PodMatrixStore {
|
|
|
266
268
|
txnId: input.txnId ?? null,
|
|
267
269
|
stateKey: input.stateKey ?? null,
|
|
268
270
|
content: input.content,
|
|
271
|
+
commandKind: 'chat',
|
|
272
|
+
surface_id: this.surfaceIdFromRoomId(input.roomId),
|
|
273
|
+
chat_id: this.surfaceIdFromRoomId(input.roomId),
|
|
269
274
|
},
|
|
270
275
|
createdAt: originIso,
|
|
271
276
|
updatedAt: originIso,
|
|
@@ -278,9 +283,9 @@ class PodMatrixStore {
|
|
|
278
283
|
.map((room) => this.chatSourceToRoomRecord(room))
|
|
279
284
|
.filter((room) => room !== undefined);
|
|
280
285
|
}
|
|
281
|
-
async listEvents(db, roomId, options = {}) {
|
|
286
|
+
async listEvents(db, roomId, context, options = {}) {
|
|
282
287
|
const conditions = [
|
|
283
|
-
(0, drizzle_solid_1.eq)(models_1.messageResource.
|
|
288
|
+
(0, drizzle_solid_1.eq)(models_1.messageResource.thread, this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(roomId), context)),
|
|
284
289
|
options.sinceTs !== undefined ? (0, drizzle_solid_1.gt)(models_1.messageResource.createdAt, new Date(options.sinceTs).toISOString()) : undefined,
|
|
285
290
|
options.beforeOrAtTs !== undefined ? (0, drizzle_solid_1.lte)(models_1.messageResource.createdAt, new Date(options.beforeOrAtTs).toISOString()) : undefined,
|
|
286
291
|
];
|
|
@@ -294,20 +299,20 @@ class PodMatrixStore {
|
|
|
294
299
|
const events = await query;
|
|
295
300
|
return events.map((event) => this.eventSourceToRecord(event));
|
|
296
301
|
}
|
|
297
|
-
async findEventByTxnId(db, roomId, txnId) {
|
|
298
|
-
const records = await this.listEvents(db, roomId);
|
|
302
|
+
async findEventByTxnId(db, roomId, txnId, context) {
|
|
303
|
+
const records = await this.listEvents(db, roomId, context);
|
|
299
304
|
return records.find((record) => record.txnId === txnId);
|
|
300
305
|
}
|
|
301
|
-
async findEventById(db, roomId, eventId) {
|
|
302
|
-
const records = await this.listEvents(db, roomId);
|
|
306
|
+
async findEventById(db, roomId, eventId, context) {
|
|
307
|
+
const records = await this.listEvents(db, roomId, context);
|
|
303
308
|
return records.find((record) => record.eventId === eventId);
|
|
304
309
|
}
|
|
305
|
-
async nextEventDepth(db, roomId) {
|
|
306
|
-
const records = await this.listEvents(db, roomId);
|
|
310
|
+
async nextEventDepth(db, roomId, context) {
|
|
311
|
+
const records = await this.listEvents(db, roomId, context);
|
|
307
312
|
return records.reduce((max, record) => Math.max(max, record.depth ?? 0), 0) + 1;
|
|
308
313
|
}
|
|
309
|
-
async findLatestStateEvent(db, roomId, eventType, stateKey) {
|
|
310
|
-
const records = await this.listEvents(db, roomId, { newestFirst: true });
|
|
314
|
+
async findLatestStateEvent(db, roomId, eventType, stateKey, context) {
|
|
315
|
+
const records = await this.listEvents(db, roomId, context, { newestFirst: true });
|
|
311
316
|
return records.find((record) => record.type === eventType && (record.stateKey ?? '') === stateKey);
|
|
312
317
|
}
|
|
313
318
|
eventSourceToRecord(source) {
|