@digimuza/saas-core 0.0.2
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/CLAUDE.md +1165 -0
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/api-keys/index.d.ts +9 -0
- package/dist/api-keys/index.d.ts.map +1 -0
- package/dist/api-keys/index.js +37 -0
- package/dist/api-keys/index.js.map +1 -0
- package/dist/api-keys/keys.d.ts +55 -0
- package/dist/api-keys/keys.d.ts.map +1 -0
- package/dist/api-keys/keys.js +92 -0
- package/dist/api-keys/keys.js.map +1 -0
- package/dist/api-keys/service.d.ts +111 -0
- package/dist/api-keys/service.d.ts.map +1 -0
- package/dist/api-keys/service.js +210 -0
- package/dist/api-keys/service.js.map +1 -0
- package/dist/audit/index.d.ts +5 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +44 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/service.d.ts +88 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +128 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/auth/client.d.ts +5 -0
- package/dist/auth/client.d.ts.map +1 -0
- package/dist/auth/client.js +26 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/auth/cookies.d.ts +51 -0
- package/dist/auth/cookies.d.ts.map +1 -0
- package/dist/auth/cookies.js +58 -0
- package/dist/auth/cookies.js.map +1 -0
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +46 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/service.d.ts +67 -0
- package/dist/auth/service.d.ts.map +1 -0
- package/dist/auth/service.js +275 -0
- package/dist/auth/service.js.map +1 -0
- package/dist/auth/types.d.ts +56 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/authorization/index.d.ts +4 -0
- package/dist/authorization/index.d.ts.map +1 -0
- package/dist/authorization/index.js +24 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/service.d.ts +92 -0
- package/dist/authorization/service.d.ts.map +1 -0
- package/dist/authorization/service.js +254 -0
- package/dist/authorization/service.js.map +1 -0
- package/dist/billing/index.d.ts +16 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +47 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/billing/provider.d.ts +114 -0
- package/dist/billing/provider.d.ts.map +1 -0
- package/dist/billing/provider.js +2 -0
- package/dist/billing/provider.js.map +1 -0
- package/dist/billing/revolut.d.ts +68 -0
- package/dist/billing/revolut.d.ts.map +1 -0
- package/dist/billing/revolut.js +181 -0
- package/dist/billing/revolut.js.map +1 -0
- package/dist/billing/service.d.ts +124 -0
- package/dist/billing/service.d.ts.map +1 -0
- package/dist/billing/service.js +470 -0
- package/dist/billing/service.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +43 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +212 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/project.d.ts +12 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +49 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/docker.d.ts +50 -0
- package/dist/cli/docker.d.ts.map +1 -0
- package/dist/cli/docker.js +84 -0
- package/dist/cli/docker.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +198 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +30 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +66 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/templates.d.ts +52 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +225 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/config/client.d.ts +60 -0
- package/dist/config/client.d.ts.map +1 -0
- package/dist/config/client.js +94 -0
- package/dist/config/client.js.map +1 -0
- package/dist/config/config-loader.d.ts +2 -0
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/config/config-loader.js +2 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/config/env.d.ts +24 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +40 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/errors.d.ts +17 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +26 -0
- package/dist/config/errors.js.map +1 -0
- package/dist/config/index.d.ts +72 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +106 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/runtime.d.ts +15 -0
- package/dist/config/runtime.d.ts.map +1 -0
- package/dist/config/runtime.js +22 -0
- package/dist/config/runtime.js.map +1 -0
- package/dist/config/sections.d.ts +226 -0
- package/dist/config/sections.d.ts.map +1 -0
- package/dist/config/sections.js +141 -0
- package/dist/config/sections.js.map +1 -0
- package/dist/db/client.d.ts +43 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +77 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/errors.d.ts +39 -0
- package/dist/db/errors.d.ts.map +1 -0
- package/dist/db/errors.js +67 -0
- package/dist/db/errors.js.map +1 -0
- package/dist/db/index.d.ts +10 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +10 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +21 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +28 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema/_shared.d.ts +30 -0
- package/dist/db/schema/_shared.d.ts.map +1 -0
- package/dist/db/schema/_shared.js +36 -0
- package/dist/db/schema/_shared.js.map +1 -0
- package/dist/db/schema/apikeys.d.ts +263 -0
- package/dist/db/schema/apikeys.d.ts.map +1 -0
- package/dist/db/schema/apikeys.js +70 -0
- package/dist/db/schema/apikeys.js.map +1 -0
- package/dist/db/schema/authorization.d.ts +465 -0
- package/dist/db/schema/authorization.d.ts.map +1 -0
- package/dist/db/schema/authorization.js +134 -0
- package/dist/db/schema/authorization.js.map +1 -0
- package/dist/db/schema/billing.d.ts +1100 -0
- package/dist/db/schema/billing.d.ts.map +1 -0
- package/dist/db/schema/billing.js +223 -0
- package/dist/db/schema/billing.js.map +1 -0
- package/dist/db/schema/events.d.ts +161 -0
- package/dist/db/schema/events.d.ts.map +1 -0
- package/dist/db/schema/events.js +66 -0
- package/dist/db/schema/events.js.map +1 -0
- package/dist/db/schema/features.d.ts +243 -0
- package/dist/db/schema/features.d.ts.map +1 -0
- package/dist/db/schema/features.js +87 -0
- package/dist/db/schema/features.js.map +1 -0
- package/dist/db/schema/files.d.ts +253 -0
- package/dist/db/schema/files.d.ts.map +1 -0
- package/dist/db/schema/files.js +74 -0
- package/dist/db/schema/files.js.map +1 -0
- package/dist/db/schema/index.d.ts +38 -0
- package/dist/db/schema/index.d.ts.map +1 -0
- package/dist/db/schema/index.js +38 -0
- package/dist/db/schema/index.js.map +1 -0
- package/dist/db/schema/invitations.d.ts +214 -0
- package/dist/db/schema/invitations.d.ts.map +1 -0
- package/dist/db/schema/invitations.js +80 -0
- package/dist/db/schema/invitations.js.map +1 -0
- package/dist/db/schema/messaging.d.ts +442 -0
- package/dist/db/schema/messaging.d.ts.map +1 -0
- package/dist/db/schema/messaging.js +120 -0
- package/dist/db/schema/messaging.js.map +1 -0
- package/dist/db/schema/users.d.ts +246 -0
- package/dist/db/schema/users.d.ts.map +1 -0
- package/dist/db/schema/users.js +60 -0
- package/dist/db/schema/users.js.map +1 -0
- package/dist/db/schema/webhooks.d.ts +693 -0
- package/dist/db/schema/webhooks.d.ts.map +1 -0
- package/dist/db/schema/webhooks.js +147 -0
- package/dist/db/schema/webhooks.js.map +1 -0
- package/dist/db/schema/workspaces.d.ts +196 -0
- package/dist/db/schema/workspaces.d.ts.map +1 -0
- package/dist/db/schema/workspaces.js +57 -0
- package/dist/db/schema/workspaces.js.map +1 -0
- package/dist/db/types.d.ts +18 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/email/adapters.d.ts +29 -0
- package/dist/email/adapters.d.ts.map +1 -0
- package/dist/email/adapters.js +60 -0
- package/dist/email/adapters.js.map +1 -0
- package/dist/email/index.d.ts +20 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +79 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/provider.d.ts +47 -0
- package/dist/email/provider.d.ts.map +1 -0
- package/dist/email/provider.js +7 -0
- package/dist/email/provider.js.map +1 -0
- package/dist/email/resend.d.ts +22 -0
- package/dist/email/resend.d.ts.map +1 -0
- package/dist/email/resend.js +51 -0
- package/dist/email/resend.js.map +1 -0
- package/dist/email/service.d.ts +55 -0
- package/dist/email/service.d.ts.map +1 -0
- package/dist/email/service.js +87 -0
- package/dist/email/service.js.map +1 -0
- package/dist/email/templates.d.ts +81 -0
- package/dist/email/templates.d.ts.map +1 -0
- package/dist/email/templates.js +84 -0
- package/dist/email/templates.js.map +1 -0
- package/dist/entitlements/index.d.ts +10 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +28 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/entitlements/service.d.ts +83 -0
- package/dist/entitlements/service.d.ts.map +1 -0
- package/dist/entitlements/service.js +158 -0
- package/dist/entitlements/service.js.map +1 -0
- package/dist/errors.d.ts +85 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +95 -0
- package/dist/errors.js.map +1 -0
- package/dist/events/core-events.d.ts +120 -0
- package/dist/events/core-events.d.ts.map +1 -0
- package/dist/events/core-events.js +109 -0
- package/dist/events/core-events.js.map +1 -0
- package/dist/events/index.d.ts +15 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +58 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/publisher.d.ts +46 -0
- package/dist/events/publisher.d.ts.map +1 -0
- package/dist/events/publisher.js +54 -0
- package/dist/events/publisher.js.map +1 -0
- package/dist/events/registry.d.ts +87 -0
- package/dist/events/registry.d.ts.map +1 -0
- package/dist/events/registry.js +34 -0
- package/dist/events/registry.js.map +1 -0
- package/dist/events/service.d.ts +78 -0
- package/dist/events/service.d.ts.map +1 -0
- package/dist/events/service.js +182 -0
- package/dist/events/service.js.map +1 -0
- package/dist/features/bucket.d.ts +22 -0
- package/dist/features/bucket.d.ts.map +1 -0
- package/dist/features/bucket.js +42 -0
- package/dist/features/bucket.js.map +1 -0
- package/dist/features/index.d.ts +15 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +78 -0
- package/dist/features/index.js.map +1 -0
- package/dist/features/registry.d.ts +51 -0
- package/dist/features/registry.d.ts.map +1 -0
- package/dist/features/registry.js +52 -0
- package/dist/features/registry.js.map +1 -0
- package/dist/features/service.d.ts +78 -0
- package/dist/features/service.d.ts.map +1 -0
- package/dist/features/service.js +207 -0
- package/dist/features/service.js.map +1 -0
- package/dist/files/index.d.ts +6 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +64 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/service.d.ts +92 -0
- package/dist/files/service.d.ts.map +1 -0
- package/dist/files/service.js +303 -0
- package/dist/files/service.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/backend.d.ts +23 -0
- package/dist/jobs/backend.d.ts.map +1 -0
- package/dist/jobs/backend.js +23 -0
- package/dist/jobs/backend.js.map +1 -0
- package/dist/jobs/index.d.ts +29 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +114 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/service.d.ts +67 -0
- package/dist/jobs/service.d.ts.map +1 -0
- package/dist/jobs/service.js +139 -0
- package/dist/jobs/service.js.map +1 -0
- package/dist/jobs/types.d.ts +78 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +4 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/logger/default.d.ts +7 -0
- package/dist/logger/default.d.ts.map +1 -0
- package/dist/logger/default.js +28 -0
- package/dist/logger/default.js.map +1 -0
- package/dist/logger/index.d.ts +24 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +90 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/redact.d.ts +40 -0
- package/dist/logger/redact.d.ts.map +1 -0
- package/dist/logger/redact.js +178 -0
- package/dist/logger/redact.js.map +1 -0
- package/dist/logger/service.d.ts +14 -0
- package/dist/logger/service.d.ts.map +1 -0
- package/dist/logger/service.js +56 -0
- package/dist/logger/service.js.map +1 -0
- package/dist/logger/sinks.d.ts +37 -0
- package/dist/logger/sinks.d.ts.map +1 -0
- package/dist/logger/sinks.js +135 -0
- package/dist/logger/sinks.js.map +1 -0
- package/dist/logger/types.d.ts +47 -0
- package/dist/logger/types.d.ts.map +1 -0
- package/dist/logger/types.js +8 -0
- package/dist/logger/types.js.map +1 -0
- package/dist/notifications/index.d.ts +8 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +72 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +79 -0
- package/dist/notifications/service.d.ts.map +1 -0
- package/dist/notifications/service.js +164 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/realtime/channels.d.ts +37 -0
- package/dist/realtime/channels.d.ts.map +1 -0
- package/dist/realtime/channels.js +58 -0
- package/dist/realtime/channels.js.map +1 -0
- package/dist/realtime/index.d.ts +19 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +118 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/postgres.d.ts +48 -0
- package/dist/realtime/postgres.d.ts.map +1 -0
- package/dist/realtime/postgres.js +151 -0
- package/dist/realtime/postgres.js.map +1 -0
- package/dist/realtime/service.d.ts +75 -0
- package/dist/realtime/service.d.ts.map +1 -0
- package/dist/realtime/service.js +103 -0
- package/dist/realtime/service.js.map +1 -0
- package/dist/realtime/sse.d.ts +55 -0
- package/dist/realtime/sse.d.ts.map +1 -0
- package/dist/realtime/sse.js +123 -0
- package/dist/realtime/sse.js.map +1 -0
- package/dist/realtime/transport.d.ts +52 -0
- package/dist/realtime/transport.d.ts.map +1 -0
- package/dist/realtime/transport.js +2 -0
- package/dist/realtime/transport.js.map +1 -0
- package/dist/storage/index.d.ts +18 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +89 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/keys.d.ts +50 -0
- package/dist/storage/keys.d.ts.map +1 -0
- package/dist/storage/keys.js +120 -0
- package/dist/storage/keys.js.map +1 -0
- package/dist/storage/memory.d.ts +32 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +84 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/provider.d.ts +93 -0
- package/dist/storage/provider.d.ts.map +1 -0
- package/dist/storage/provider.js +2 -0
- package/dist/storage/provider.js.map +1 -0
- package/dist/storage/s3.d.ts +34 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +175 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/service.d.ts +86 -0
- package/dist/storage/service.d.ts.map +1 -0
- package/dist/storage/service.js +107 -0
- package/dist/storage/service.js.map +1 -0
- package/dist/storage/sigv4.d.ts +58 -0
- package/dist/storage/sigv4.d.ts.map +1 -0
- package/dist/storage/sigv4.js +114 -0
- package/dist/storage/sigv4.js.map +1 -0
- package/dist/streams/client.d.ts +91 -0
- package/dist/streams/client.d.ts.map +1 -0
- package/dist/streams/client.js +128 -0
- package/dist/streams/client.js.map +1 -0
- package/dist/streams/events.d.ts +68 -0
- package/dist/streams/events.d.ts.map +1 -0
- package/dist/streams/events.js +81 -0
- package/dist/streams/events.js.map +1 -0
- package/dist/streams/index.d.ts +47 -0
- package/dist/streams/index.d.ts.map +1 -0
- package/dist/streams/index.js +47 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/realtime.d.ts +27 -0
- package/dist/streams/realtime.d.ts.map +1 -0
- package/dist/streams/realtime.js +50 -0
- package/dist/streams/realtime.js.map +1 -0
- package/dist/streams/state.d.ts +26 -0
- package/dist/streams/state.d.ts.map +1 -0
- package/dist/streams/state.js +34 -0
- package/dist/streams/state.js.map +1 -0
- package/dist/users/index.d.ts +9 -0
- package/dist/users/index.d.ts.map +1 -0
- package/dist/users/index.js +23 -0
- package/dist/users/index.js.map +1 -0
- package/dist/users/service.d.ts +43 -0
- package/dist/users/service.d.ts.map +1 -0
- package/dist/users/service.js +113 -0
- package/dist/users/service.js.map +1 -0
- package/dist/webhooks/inbound.d.ts +70 -0
- package/dist/webhooks/inbound.d.ts.map +1 -0
- package/dist/webhooks/inbound.js +146 -0
- package/dist/webhooks/inbound.js.map +1 -0
- package/dist/webhooks/index.d.ts +12 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +65 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/outgoing.d.ts +89 -0
- package/dist/webhooks/outgoing.d.ts.map +1 -0
- package/dist/webhooks/outgoing.js +375 -0
- package/dist/webhooks/outgoing.js.map +1 -0
- package/dist/webhooks/signature.d.ts +40 -0
- package/dist/webhooks/signature.d.ts.map +1 -0
- package/dist/webhooks/signature.js +77 -0
- package/dist/webhooks/signature.js.map +1 -0
- package/dist/workspaces/context.d.ts +30 -0
- package/dist/workspaces/context.d.ts.map +1 -0
- package/dist/workspaces/context.js +12 -0
- package/dist/workspaces/context.js.map +1 -0
- package/dist/workspaces/index.d.ts +5 -0
- package/dist/workspaces/index.d.ts.map +1 -0
- package/dist/workspaces/index.js +21 -0
- package/dist/workspaces/index.js.map +1 -0
- package/dist/workspaces/service.d.ts +126 -0
- package/dist/workspaces/service.d.ts.map +1 -0
- package/dist/workspaces/service.js +495 -0
- package/dist/workspaces/service.js.map +1 -0
- package/docs/README.md +71 -0
- package/docs/api-keys.md +184 -0
- package/docs/audit.md +198 -0
- package/docs/auth.md +196 -0
- package/docs/authorization.md +225 -0
- package/docs/billing.md +293 -0
- package/docs/cli.md +238 -0
- package/docs/config.md +163 -0
- package/docs/db.md +219 -0
- package/docs/email.md +222 -0
- package/docs/entitlements.md +194 -0
- package/docs/errors.md +158 -0
- package/docs/events.md +279 -0
- package/docs/feature-flags.md +237 -0
- package/docs/files.md +229 -0
- package/docs/jobs.md +288 -0
- package/docs/logger.md +269 -0
- package/docs/notifications.md +179 -0
- package/docs/publishing.md +128 -0
- package/docs/realtime.md +360 -0
- package/docs/storage.md +279 -0
- package/docs/streams.md +296 -0
- package/docs/users.md +117 -0
- package/docs/webhooks.md +272 -0
- package/docs/workspaces.md +269 -0
- package/drizzle/0000_init_users.sql +21 -0
- package/drizzle/0001_workspaces_roles_permissions.sql +86 -0
- package/drizzle/0002_billing_entitlements.sql +97 -0
- package/drizzle/0003_events.sql +17 -0
- package/drizzle/0004_notifications_audit.sql +64 -0
- package/drizzle/0005_api_keys_webhooks.sql +77 -0
- package/drizzle/0006_feature_flags.sql +22 -0
- package/drizzle/0007_files.sql +23 -0
- package/drizzle/meta/0000_snapshot.json +160 -0
- package/drizzle/meta/0001_snapshot.json +837 -0
- package/drizzle/meta/0002_snapshot.json +1580 -0
- package/drizzle/meta/0003_snapshot.json +1751 -0
- package/drizzle/meta/0004_snapshot.json +2109 -0
- package/drizzle/meta/0005_snapshot.json +2719 -0
- package/drizzle/meta/0006_snapshot.json +2909 -0
- package/drizzle/meta/0007_snapshot.json +3113 -0
- package/drizzle/meta/_journal.json +62 -0
- package/package.json +180 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public storage surface: `@digimuza/saas-core/storage`. Server-only.
|
|
3
|
+
*
|
|
4
|
+
* Object storage behind an adapter, with tenant scoping that cannot be bypassed.
|
|
5
|
+
*
|
|
6
|
+
* There is deliberately **no database table**. An object is referenced by key from
|
|
7
|
+
* whichever product table owns it, so the core does not impose a file model —
|
|
8
|
+
* a table would have to guess at metadata, ownership and lifecycle that only the
|
|
9
|
+
* product knows.
|
|
10
|
+
*
|
|
11
|
+
* ## Setup
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { storage } from "@digimuza/saas-core/storage";
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Or build your own — a different store, or a fake in tests:
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { createStorageService, createMemoryStorageProvider } from "@digimuza/saas-core/storage";
|
|
21
|
+
*
|
|
22
|
+
* const storage = createStorageService({ provider: createMemoryStorageProvider() });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ## Everything goes through a workspace
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const files = storage.forWorkspace(context);
|
|
29
|
+
*
|
|
30
|
+
* await files.upload({ path: "avatars/me.png", body, contentType: "image/png" });
|
|
31
|
+
* const url = await files.getUrl("avatars/me.png");
|
|
32
|
+
* await files.delete("avatars/me.png");
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* `forWorkspace` takes a verified `WorkspaceContext`, and the scoped API takes
|
|
36
|
+
* *paths* rather than keys — so `workspaces/<id>/` is applied in one place and a
|
|
37
|
+
* caller has no way to address another tenant's objects. Store `files.keyFor(path)`
|
|
38
|
+
* in your own tables, and pass it back through `urlForKey`, which re-checks
|
|
39
|
+
* ownership.
|
|
40
|
+
*
|
|
41
|
+
* ## Direct browser uploads
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* const uploadUrl = await files.createUploadUrl("imports/data.csv", {
|
|
45
|
+
* contentType: "text/csv",
|
|
46
|
+
* expiresInSeconds: 600,
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Hand that to the browser and let it `PUT` the bytes. Proxying uploads through
|
|
51
|
+
* the application means a request that holds a server for the whole transfer, and
|
|
52
|
+
* a body limit on every platform in the path.
|
|
53
|
+
*/
|
|
54
|
+
import { config } from "../config/index.js";
|
|
55
|
+
import { createS3Provider } from "./s3.js";
|
|
56
|
+
import { createStorageService } from "./service.js";
|
|
57
|
+
export { assertKeyBelongsTo, assertObjectPath, isValidObjectPath, MAX_OBJECT_KEY_LENGTH, parseWorkspaceObjectKey, WORKSPACE_PREFIX, workspaceObjectKey, } from "./keys.js";
|
|
58
|
+
export { bodyBytes, createMemoryStorageProvider, } from "./memory.js";
|
|
59
|
+
export { createS3Provider, objectDigest } from "./s3.js";
|
|
60
|
+
export { assertObjectExists, createStorageService, MAX_SIGNED_URL_SECONDS, } from "./service.js";
|
|
61
|
+
export { encodeObjectPath, presign, signingKey, uriEncode, } from "./sigv4.js";
|
|
62
|
+
/** An S3-compatible provider built from the `storage` configuration section. */
|
|
63
|
+
export function createConfiguredStorageProvider() {
|
|
64
|
+
const storage = config.storage;
|
|
65
|
+
return createS3Provider({
|
|
66
|
+
bucket: storage.bucket,
|
|
67
|
+
region: storage.region,
|
|
68
|
+
credentials: {
|
|
69
|
+
accessKeyId: storage.accessKeyId,
|
|
70
|
+
secretAccessKey: storage.secretAccessKey,
|
|
71
|
+
},
|
|
72
|
+
...(storage.endpoint !== undefined ? { endpoint: storage.endpoint } : {}),
|
|
73
|
+
...(storage.publicUrl !== undefined ? { publicBaseUrl: storage.publicUrl } : {}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
let configuredProvider;
|
|
77
|
+
/**
|
|
78
|
+
* Default service, bound to configuration.
|
|
79
|
+
*
|
|
80
|
+
* The provider is a getter, so the `storage` configuration section resolves on
|
|
81
|
+
* first use — importing this module does not require credentials.
|
|
82
|
+
*/
|
|
83
|
+
export const storage = createStorageService({
|
|
84
|
+
get provider() {
|
|
85
|
+
configuredProvider ??= createConfiguredStorageProvider();
|
|
86
|
+
return configuredProvider;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAuB,MAAM,cAAc,CAAC;AAGzE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,2BAA2B,GAI5B,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAEjF,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GAOvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,SAAS,GAIV,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,MAAM,UAAU,+BAA+B;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAE/B,OAAO,gBAAgB,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE;YACX,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,eAAe,EAAE,OAAO,CAAC,eAAe;SACzC;QACD,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjF,CAAC,CAAC;AACL,CAAC;AAED,IAAI,kBAA+C,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAmB,oBAAoB,CAAC;IAC1D,IAAI,QAAQ;QACV,kBAAkB,KAAK,+BAA+B,EAAE,CAAC;QACzD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object key validation and tenant scoping.
|
|
3
|
+
*
|
|
4
|
+
* This is the security surface of the module. Object keys are paths, and a caller
|
|
5
|
+
* that can put `../` into one can read out of its own prefix and into another
|
|
6
|
+
* tenant's — a cross-tenant read with no database involved and nothing in an audit
|
|
7
|
+
* log. So keys are validated before they are ever concatenated with a prefix,
|
|
8
|
+
* never after.
|
|
9
|
+
*/
|
|
10
|
+
/** S3 caps a key at 1024 bytes; the same limit is a sane ceiling everywhere. */
|
|
11
|
+
export declare const MAX_OBJECT_KEY_LENGTH = 1024;
|
|
12
|
+
/** Prefix every workspace-scoped object lives under. */
|
|
13
|
+
export declare const WORKSPACE_PREFIX = "workspaces";
|
|
14
|
+
/**
|
|
15
|
+
* Validate a caller-supplied object path.
|
|
16
|
+
*
|
|
17
|
+
* Rejects rather than sanitises. Silently rewriting `../secret` to `secret` would
|
|
18
|
+
* store the object somewhere the caller did not ask for, and a caller who meant
|
|
19
|
+
* to traverse deserves an error rather than a surprise.
|
|
20
|
+
*/
|
|
21
|
+
export declare function assertObjectPath(path: string): void;
|
|
22
|
+
/** True when {@link assertObjectPath} would accept the path. */
|
|
23
|
+
export declare function isValidObjectPath(path: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Build the fully-qualified key for a workspace-scoped object.
|
|
26
|
+
*
|
|
27
|
+
* The workspace id is checked as a UUID rather than trusted, because it is the
|
|
28
|
+
* only thing separating one tenant's objects from another's. A caller passing a
|
|
29
|
+
* malformed id would otherwise create a prefix that could collide.
|
|
30
|
+
*/
|
|
31
|
+
export declare function workspaceObjectKey(workspaceId: string, path: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Recover the workspace id and path from a scoped key.
|
|
34
|
+
*
|
|
35
|
+
* Returns `undefined` for anything that is not one, so a caller can tell a scoped
|
|
36
|
+
* key from an unscoped one rather than guessing.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseWorkspaceObjectKey(key: string): {
|
|
39
|
+
workspaceId: string;
|
|
40
|
+
path: string;
|
|
41
|
+
} | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Assert a key belongs to a workspace.
|
|
44
|
+
*
|
|
45
|
+
* The check that turns a stored key back into something safe to act on: a key
|
|
46
|
+
* read from a product table might have been written before a bug was fixed, or by
|
|
47
|
+
* a different tenant entirely.
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertKeyBelongsTo(workspaceId: string, key: string): void;
|
|
50
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/storage/keys.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAO7C;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA6CnD;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAO5E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,GACV;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAanD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOzE"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { InvalidInputError } from "../errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Object key validation and tenant scoping.
|
|
4
|
+
*
|
|
5
|
+
* This is the security surface of the module. Object keys are paths, and a caller
|
|
6
|
+
* that can put `../` into one can read out of its own prefix and into another
|
|
7
|
+
* tenant's — a cross-tenant read with no database involved and nothing in an audit
|
|
8
|
+
* log. So keys are validated before they are ever concatenated with a prefix,
|
|
9
|
+
* never after.
|
|
10
|
+
*/
|
|
11
|
+
/** S3 caps a key at 1024 bytes; the same limit is a sane ceiling everywhere. */
|
|
12
|
+
export const MAX_OBJECT_KEY_LENGTH = 1024;
|
|
13
|
+
/** Prefix every workspace-scoped object lives under. */
|
|
14
|
+
export const WORKSPACE_PREFIX = "workspaces";
|
|
15
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
16
|
+
/** Control characters, including NUL. Built from escapes, never literals. */
|
|
17
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
18
|
+
/**
|
|
19
|
+
* Validate a caller-supplied object path.
|
|
20
|
+
*
|
|
21
|
+
* Rejects rather than sanitises. Silently rewriting `../secret` to `secret` would
|
|
22
|
+
* store the object somewhere the caller did not ask for, and a caller who meant
|
|
23
|
+
* to traverse deserves an error rather than a surprise.
|
|
24
|
+
*/
|
|
25
|
+
export function assertObjectPath(path) {
|
|
26
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
27
|
+
throw new InvalidInputError("An object path is required.");
|
|
28
|
+
}
|
|
29
|
+
if (Buffer.byteLength(path, "utf8") > MAX_OBJECT_KEY_LENGTH) {
|
|
30
|
+
throw new InvalidInputError(`An object path may not exceed ${MAX_OBJECT_KEY_LENGTH} bytes.`);
|
|
31
|
+
}
|
|
32
|
+
// A leading slash makes the key absolute and defeats prefixing entirely.
|
|
33
|
+
if (path.startsWith("/")) {
|
|
34
|
+
throw new InvalidInputError("An object path must be relative.");
|
|
35
|
+
}
|
|
36
|
+
// Backslashes are path separators on some receivers and data on others.
|
|
37
|
+
if (path.includes("\\")) {
|
|
38
|
+
throw new InvalidInputError("An object path may not contain a backslash.");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A NUL can truncate a key inside a C-based backend, so `a<NUL>../b` might be
|
|
42
|
+
* stored as `a` — traversal smuggled past a naive segment check.
|
|
43
|
+
*/
|
|
44
|
+
if (CONTROL_CHARACTERS.test(path)) {
|
|
45
|
+
throw new InvalidInputError("An object path may not contain control characters.");
|
|
46
|
+
}
|
|
47
|
+
for (const segment of path.split("/")) {
|
|
48
|
+
if (segment.length === 0) {
|
|
49
|
+
// `a//b` and a trailing slash both produce an empty segment.
|
|
50
|
+
throw new InvalidInputError("An object path may not contain an empty segment.");
|
|
51
|
+
}
|
|
52
|
+
if (segment === "." || segment === "..") {
|
|
53
|
+
throw new InvalidInputError("An object path may not contain relative segments.");
|
|
54
|
+
}
|
|
55
|
+
if (segment !== segment.trim()) {
|
|
56
|
+
/**
|
|
57
|
+
* Leading or trailing whitespace is legal in S3 but invisible in every UI,
|
|
58
|
+
* which makes two objects that look identical impossible to tell apart.
|
|
59
|
+
*/
|
|
60
|
+
throw new InvalidInputError("An object path segment may not be padded with whitespace.");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** True when {@link assertObjectPath} would accept the path. */
|
|
65
|
+
export function isValidObjectPath(path) {
|
|
66
|
+
try {
|
|
67
|
+
assertObjectPath(path);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the fully-qualified key for a workspace-scoped object.
|
|
76
|
+
*
|
|
77
|
+
* The workspace id is checked as a UUID rather than trusted, because it is the
|
|
78
|
+
* only thing separating one tenant's objects from another's. A caller passing a
|
|
79
|
+
* malformed id would otherwise create a prefix that could collide.
|
|
80
|
+
*/
|
|
81
|
+
export function workspaceObjectKey(workspaceId, path) {
|
|
82
|
+
if (!UUID.test(workspaceId)) {
|
|
83
|
+
throw new InvalidInputError("A workspace id must be a UUID.");
|
|
84
|
+
}
|
|
85
|
+
assertObjectPath(path);
|
|
86
|
+
return `${WORKSPACE_PREFIX}/${workspaceId}/${path}`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Recover the workspace id and path from a scoped key.
|
|
90
|
+
*
|
|
91
|
+
* Returns `undefined` for anything that is not one, so a caller can tell a scoped
|
|
92
|
+
* key from an unscoped one rather than guessing.
|
|
93
|
+
*/
|
|
94
|
+
export function parseWorkspaceObjectKey(key) {
|
|
95
|
+
const parts = key.split("/");
|
|
96
|
+
if (parts.length < 3 || parts[0] !== WORKSPACE_PREFIX) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const workspaceId = parts[1];
|
|
100
|
+
if (!UUID.test(workspaceId)) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const path = parts.slice(2).join("/");
|
|
104
|
+
return isValidObjectPath(path) ? { workspaceId, path } : undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Assert a key belongs to a workspace.
|
|
108
|
+
*
|
|
109
|
+
* The check that turns a stored key back into something safe to act on: a key
|
|
110
|
+
* read from a product table might have been written before a bug was fixed, or by
|
|
111
|
+
* a different tenant entirely.
|
|
112
|
+
*/
|
|
113
|
+
export function assertKeyBelongsTo(workspaceId, key) {
|
|
114
|
+
const parsed = parseWorkspaceObjectKey(key);
|
|
115
|
+
if (parsed === undefined || parsed.workspaceId.toLowerCase() !== workspaceId.toLowerCase()) {
|
|
116
|
+
// Deliberately does not say which case failed.
|
|
117
|
+
throw new InvalidInputError("Object key does not belong to this workspace.");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/storage/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ObjectBody, StorageProvider } from "./provider.ts";
|
|
2
|
+
export interface MemoryObject {
|
|
3
|
+
readonly key: string;
|
|
4
|
+
readonly body: Uint8Array;
|
|
5
|
+
readonly contentType?: string;
|
|
6
|
+
readonly cacheControl?: string;
|
|
7
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
8
|
+
}
|
|
9
|
+
export interface MemoryStorageProvider extends StorageProvider {
|
|
10
|
+
readonly objects: Map<string, MemoryObject>;
|
|
11
|
+
/** Decode a stored object as text, for assertions. */
|
|
12
|
+
text(key: string): string | undefined;
|
|
13
|
+
/** Every key under a prefix. Useful for asserting tenant scoping. */
|
|
14
|
+
keysUnder(prefix: string): string[];
|
|
15
|
+
clear(): void;
|
|
16
|
+
}
|
|
17
|
+
export interface MemoryStorageOptions {
|
|
18
|
+
/** Returned by `publicUrl`. Omit to model a private bucket. */
|
|
19
|
+
readonly publicBaseUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* An in-memory object store.
|
|
23
|
+
*
|
|
24
|
+
* For tests, and for a local development loop that should not need credentials.
|
|
25
|
+
* Signed URLs are synthesised — they carry an expiry and a signature-shaped token
|
|
26
|
+
* so a test can assert on them, but nothing verifies them. Do not mistake this for
|
|
27
|
+
* a store.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createMemoryStorageProvider(options?: MemoryStorageOptions): MemoryStorageProvider;
|
|
30
|
+
/** Bytes of a body, for assertions that do not care about encoding. */
|
|
31
|
+
export declare function bodyBytes(body: ObjectBody): Uint8Array;
|
|
32
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EAIV,eAAe,EAEhB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC5C,sDAAsD;IACtD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,qEAAqE;IACrE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,oBAAyB,GACjC,qBAAqB,CAkGvB;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEtD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* An in-memory object store.
|
|
4
|
+
*
|
|
5
|
+
* For tests, and for a local development loop that should not need credentials.
|
|
6
|
+
* Signed URLs are synthesised — they carry an expiry and a signature-shaped token
|
|
7
|
+
* so a test can assert on them, but nothing verifies them. Do not mistake this for
|
|
8
|
+
* a store.
|
|
9
|
+
*/
|
|
10
|
+
export function createMemoryStorageProvider(options = {}) {
|
|
11
|
+
const objects = new Map();
|
|
12
|
+
function fakeToken(key, method, expiresAt) {
|
|
13
|
+
return createHash("sha256").update(`${method}:${key}:${expiresAt}`).digest("hex").slice(0, 32);
|
|
14
|
+
}
|
|
15
|
+
function signed(key, method, expiresInSeconds, extra = "") {
|
|
16
|
+
const expiresAt = Date.now() + expiresInSeconds * 1000;
|
|
17
|
+
return (`memory://objects/${encodeURIComponent(key)}` +
|
|
18
|
+
`?method=${method}&expires=${expiresAt}&signature=${fakeToken(key, method, expiresAt)}${extra}`);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
name: "memory",
|
|
22
|
+
objects,
|
|
23
|
+
async put(input) {
|
|
24
|
+
const body = typeof input.body === "string" ? new TextEncoder().encode(input.body) : input.body;
|
|
25
|
+
objects.set(input.key, {
|
|
26
|
+
key: input.key,
|
|
27
|
+
body,
|
|
28
|
+
...(input.contentType !== undefined ? { contentType: input.contentType } : {}),
|
|
29
|
+
...(input.cacheControl !== undefined ? { cacheControl: input.cacheControl } : {}),
|
|
30
|
+
...(input.metadata !== undefined ? { metadata: input.metadata } : {}),
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
key: input.key,
|
|
34
|
+
size: body.byteLength,
|
|
35
|
+
etag: createHash("md5").update(body).digest("hex"),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
async delete(key) {
|
|
39
|
+
objects.delete(key);
|
|
40
|
+
},
|
|
41
|
+
async exists(key) {
|
|
42
|
+
return objects.has(key);
|
|
43
|
+
},
|
|
44
|
+
async stat(key) {
|
|
45
|
+
const object = objects.get(key);
|
|
46
|
+
if (object === undefined) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
size: object.body.byteLength,
|
|
51
|
+
...(object.contentType !== undefined ? { contentType: object.contentType } : {}),
|
|
52
|
+
etag: createHash("md5").update(object.body).digest("hex"),
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
publicUrl(key) {
|
|
56
|
+
return options.publicBaseUrl === undefined
|
|
57
|
+
? undefined
|
|
58
|
+
: `${options.publicBaseUrl.replace(/\/+$/, "")}/${key}`;
|
|
59
|
+
},
|
|
60
|
+
async signedDownloadUrl(input) {
|
|
61
|
+
return signed(input.key, "GET", input.expiresInSeconds, input.downloadFilename === undefined
|
|
62
|
+
? ""
|
|
63
|
+
: `&filename=${encodeURIComponent(input.downloadFilename)}`);
|
|
64
|
+
},
|
|
65
|
+
async signedUploadUrl(input) {
|
|
66
|
+
return signed(input.key, "PUT", input.expiresInSeconds, input.contentType === undefined ? "" : `&type=${encodeURIComponent(input.contentType)}`);
|
|
67
|
+
},
|
|
68
|
+
text(key) {
|
|
69
|
+
const object = objects.get(key);
|
|
70
|
+
return object === undefined ? undefined : new TextDecoder().decode(object.body);
|
|
71
|
+
},
|
|
72
|
+
keysUnder(prefix) {
|
|
73
|
+
return [...objects.keys()].filter((key) => key.startsWith(prefix)).sort();
|
|
74
|
+
},
|
|
75
|
+
clear() {
|
|
76
|
+
objects.clear();
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** Bytes of a body, for assertions that do not care about encoding. */
|
|
81
|
+
export function bodyBytes(body) {
|
|
82
|
+
return typeof body === "string" ? new TextEncoder().encode(body) : body;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Bytes this package will accept for an upload. */
|
|
2
|
+
export type ObjectBody = Uint8Array | string;
|
|
3
|
+
export interface PutObjectInput {
|
|
4
|
+
/** Fully-qualified key. Already validated and scoped by the service. */
|
|
5
|
+
readonly key: string;
|
|
6
|
+
readonly body: ObjectBody;
|
|
7
|
+
readonly contentType?: string;
|
|
8
|
+
/** `Cache-Control` for the stored object. */
|
|
9
|
+
readonly cacheControl?: string;
|
|
10
|
+
/** Provider metadata, where supported. Never put a secret here. */
|
|
11
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
12
|
+
}
|
|
13
|
+
export interface StoredObject {
|
|
14
|
+
readonly key: string;
|
|
15
|
+
readonly size: number;
|
|
16
|
+
/** Provider entity tag, when it returns one. */
|
|
17
|
+
readonly etag?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SignedUrlInput {
|
|
20
|
+
readonly key: string;
|
|
21
|
+
readonly expiresInSeconds: number;
|
|
22
|
+
}
|
|
23
|
+
export interface SignedDownloadInput extends SignedUrlInput {
|
|
24
|
+
/**
|
|
25
|
+
* Forces a download with this filename.
|
|
26
|
+
*
|
|
27
|
+
* Also the safe way to serve user-uploaded content: `attachment` stops a
|
|
28
|
+
* browser rendering an uploaded HTML or SVG file in your origin, which is
|
|
29
|
+
* stored XSS.
|
|
30
|
+
*/
|
|
31
|
+
readonly downloadFilename?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SignedUploadInput extends SignedUrlInput {
|
|
34
|
+
/**
|
|
35
|
+
* Signed into the URL, so the client must send exactly this `Content-Type`.
|
|
36
|
+
*
|
|
37
|
+
* Worth setting: without it a client can upload anything and declare it
|
|
38
|
+
* anything.
|
|
39
|
+
*/
|
|
40
|
+
readonly contentType?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The seam between the core and an object store.
|
|
44
|
+
*
|
|
45
|
+
* Six methods. Everything above this interface is provider-independent, so moving
|
|
46
|
+
* from S3 to R2 to a local disk is an adapter rather than a migration — and
|
|
47
|
+
* nothing in product code has to know which one is in use.
|
|
48
|
+
*
|
|
49
|
+
* Implementations do **no** key validation or tenant scoping. Both happen once, in
|
|
50
|
+
* the service, before a key reaches here; a provider that also checked would give
|
|
51
|
+
* the rule two homes and one of them would drift.
|
|
52
|
+
*/
|
|
53
|
+
/** What a store can tell us about an object without downloading it. */
|
|
54
|
+
export interface ObjectStat {
|
|
55
|
+
readonly size: number;
|
|
56
|
+
readonly contentType?: string;
|
|
57
|
+
readonly etag?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface StorageProvider {
|
|
60
|
+
readonly name: string;
|
|
61
|
+
put(input: PutObjectInput): Promise<StoredObject>;
|
|
62
|
+
delete(key: string): Promise<void>;
|
|
63
|
+
exists(key: string): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Object metadata, or `undefined` when there is none.
|
|
66
|
+
*
|
|
67
|
+
* Optional, because not every conceivable store can answer it — but it is what
|
|
68
|
+
* makes a direct browser upload trustworthy. A presigned `PUT` cannot enforce a
|
|
69
|
+
* size, so the only way to know what a client actually sent is to ask
|
|
70
|
+
* afterwards. Without this, a client declaring 1 KB and uploading 5 GB goes
|
|
71
|
+
* unnoticed.
|
|
72
|
+
*/
|
|
73
|
+
stat?(key: string): Promise<ObjectStat | undefined>;
|
|
74
|
+
/**
|
|
75
|
+
* A permanently public URL, or `undefined` when the store is private.
|
|
76
|
+
*
|
|
77
|
+
* Callers must handle `undefined` rather than assume a URL: a private bucket is
|
|
78
|
+
* the correct default for user uploads, and only a deployment with a public CDN
|
|
79
|
+
* origin can answer this.
|
|
80
|
+
*/
|
|
81
|
+
publicUrl(key: string): string | undefined;
|
|
82
|
+
/** A time-limited URL for reading a private object. */
|
|
83
|
+
signedDownloadUrl(input: SignedDownloadInput): Promise<string>;
|
|
84
|
+
/**
|
|
85
|
+
* A time-limited URL the browser can `PUT` to directly.
|
|
86
|
+
*
|
|
87
|
+
* The reason this interface exists in the shape it does: proxying uploads
|
|
88
|
+
* through the application means a request that holds a server for the length of
|
|
89
|
+
* the transfer, and a body limit on every platform in the path.
|
|
90
|
+
*/
|
|
91
|
+
signedUploadUrl(input: SignedUploadInput): Promise<string>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/storage/provider.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;GAUG;AACH,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtC;;;;;;;;OAQG;IACH,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAEpD;;;;;;OAMG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C,uDAAuD;IACvD,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/D;;;;;;OAMG;IACH,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/storage/provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ObjectBody, StorageProvider } from "./provider.ts";
|
|
2
|
+
import { type SigV4Credentials } from "./sigv4.ts";
|
|
3
|
+
export interface S3ProviderOptions {
|
|
4
|
+
readonly bucket: string;
|
|
5
|
+
readonly region: string;
|
|
6
|
+
readonly credentials: SigV4Credentials;
|
|
7
|
+
/**
|
|
8
|
+
* Custom endpoint for an S3-compatible store — R2, MinIO, Backblaze, Supabase.
|
|
9
|
+
* Omit for AWS.
|
|
10
|
+
*/
|
|
11
|
+
readonly endpoint?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Put the bucket in the path rather than the host.
|
|
14
|
+
*
|
|
15
|
+
* Required by MinIO and most self-hosted stores, which cannot do wildcard
|
|
16
|
+
* subdomains. Defaults to true when an endpoint is given, false for AWS.
|
|
17
|
+
*/
|
|
18
|
+
readonly forcePathStyle?: boolean;
|
|
19
|
+
/** CDN or public origin, when the bucket is publicly readable. */
|
|
20
|
+
readonly publicBaseUrl?: string;
|
|
21
|
+
readonly fetchImpl?: typeof fetch;
|
|
22
|
+
readonly now?: () => Date;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* S3 and S3-compatible object storage.
|
|
26
|
+
*
|
|
27
|
+
* Uses SigV4 presigned URLs for reads and browser uploads, and a signed `PUT`
|
|
28
|
+
* over `fetch` for server-side writes. No AWS SDK: see `sigv4.ts` for why, and
|
|
29
|
+
* note that the signing itself is verified against AWS's published test vector.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createS3Provider(options: S3ProviderOptions): StorageProvider;
|
|
32
|
+
/** Content hash, for deduplicating or naming objects by content. */
|
|
33
|
+
export declare function objectDigest(body: ObjectBody): string;
|
|
34
|
+
//# sourceMappingURL=s3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EAKV,eAAe,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,eAAe,CA8L5E;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAErD"}
|