@dotdo/do 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -0
- package/dist/ai/embeddings.d.ts +129 -0
- package/dist/ai/embeddings.d.ts.map +1 -0
- package/dist/ai/embeddings.js +217 -0
- package/dist/ai/embeddings.js.map +1 -0
- package/dist/ai/gateway.d.ts +139 -0
- package/dist/ai/gateway.d.ts.map +1 -0
- package/dist/ai/gateway.js +179 -0
- package/dist/ai/gateway.js.map +1 -0
- package/dist/ai/image.d.ts +140 -0
- package/dist/ai/image.d.ts.map +1 -0
- package/dist/ai/image.js +199 -0
- package/dist/ai/image.js.map +1 -0
- package/dist/ai/index.d.ts +98 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +223 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/models.d.ts +81 -0
- package/dist/ai/models.d.ts.map +1 -0
- package/dist/ai/models.js +537 -0
- package/dist/ai/models.js.map +1 -0
- package/dist/ai/text.d.ts +176 -0
- package/dist/ai/text.d.ts.map +1 -0
- package/dist/ai/text.js +253 -0
- package/dist/ai/text.js.map +1 -0
- package/dist/ai/voice/agents.d.ts +224 -0
- package/dist/ai/voice/agents.d.ts.map +1 -0
- package/dist/ai/voice/agents.js +375 -0
- package/dist/ai/voice/agents.js.map +1 -0
- package/dist/ai/voice/campaigns.d.ts +307 -0
- package/dist/ai/voice/campaigns.d.ts.map +1 -0
- package/dist/ai/voice/campaigns.js +739 -0
- package/dist/ai/voice/campaigns.js.map +1 -0
- package/dist/ai/voice/index.d.ts +21 -0
- package/dist/ai/voice/index.d.ts.map +1 -0
- package/dist/ai/voice/index.js +42 -0
- package/dist/ai/voice/index.js.map +1 -0
- package/dist/ai/voice/providers.d.ts +283 -0
- package/dist/ai/voice/providers.d.ts.map +1 -0
- package/dist/ai/voice/providers.js +286 -0
- package/dist/ai/voice/providers.js.map +1 -0
- package/dist/ai/voice/sessions.d.ts +294 -0
- package/dist/ai/voice/sessions.d.ts.map +1 -0
- package/dist/ai/voice/sessions.js +531 -0
- package/dist/ai/voice/sessions.js.map +1 -0
- package/dist/ai/voice/tools.d.ts +242 -0
- package/dist/ai/voice/tools.d.ts.map +1 -0
- package/dist/ai/voice/tools.js +370 -0
- package/dist/ai/voice/tools.js.map +1 -0
- package/dist/ai/voice/tts.d.ts +173 -0
- package/dist/ai/voice/tts.d.ts.map +1 -0
- package/dist/ai/voice/tts.js +252 -0
- package/dist/ai/voice/tts.js.map +1 -0
- package/dist/ai/voice/webrtc.d.ts +228 -0
- package/dist/ai/voice/webrtc.d.ts.map +1 -0
- package/dist/ai/voice/webrtc.js +372 -0
- package/dist/ai/voice/webrtc.js.map +1 -0
- package/dist/api/index.d.ts +103 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +191 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/mcp/handlers.d.ts +25 -0
- package/dist/api/mcp/handlers.d.ts.map +1 -0
- package/dist/api/mcp/handlers.js +422 -0
- package/dist/api/mcp/handlers.js.map +1 -0
- package/dist/api/mcp/index.d.ts +113 -0
- package/dist/api/mcp/index.d.ts.map +1 -0
- package/dist/api/mcp/index.js +141 -0
- package/dist/api/mcp/index.js.map +1 -0
- package/dist/api/middleware/auth.d.ts +65 -0
- package/dist/api/middleware/auth.d.ts.map +1 -0
- package/dist/api/middleware/auth.js +271 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/api/middleware/cors.d.ts +62 -0
- package/dist/api/middleware/cors.d.ts.map +1 -0
- package/dist/api/middleware/cors.js +225 -0
- package/dist/api/middleware/cors.js.map +1 -0
- package/dist/api/middleware/index.d.ts +60 -0
- package/dist/api/middleware/index.d.ts.map +1 -0
- package/dist/api/middleware/index.js +175 -0
- package/dist/api/middleware/index.js.map +1 -0
- package/dist/api/middleware/rateLimit.d.ts +84 -0
- package/dist/api/middleware/rateLimit.d.ts.map +1 -0
- package/dist/api/middleware/rateLimit.js +321 -0
- package/dist/api/middleware/rateLimit.js.map +1 -0
- package/dist/api/routes/ai.d.ts +17 -0
- package/dist/api/routes/ai.d.ts.map +1 -0
- package/dist/api/routes/ai.js +430 -0
- package/dist/api/routes/ai.js.map +1 -0
- package/dist/api/routes/do.d.ts +17 -0
- package/dist/api/routes/do.d.ts.map +1 -0
- package/dist/api/routes/do.js +458 -0
- package/dist/api/routes/do.js.map +1 -0
- package/dist/api/routes/functions.d.ts +111 -0
- package/dist/api/routes/functions.d.ts.map +1 -0
- package/dist/api/routes/functions.js +548 -0
- package/dist/api/routes/functions.js.map +1 -0
- package/dist/api/routes/health.d.ts +16 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +163 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/index.d.ts +41 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/index.js +275 -0
- package/dist/api/routes/index.js.map +1 -0
- package/dist/api/routes/nouns.d.ts +26 -0
- package/dist/api/routes/nouns.d.ts.map +1 -0
- package/dist/api/routes/nouns.js +456 -0
- package/dist/api/routes/nouns.js.map +1 -0
- package/dist/api/routes/orgs.d.ts +17 -0
- package/dist/api/routes/orgs.d.ts.map +1 -0
- package/dist/api/routes/orgs.js +560 -0
- package/dist/api/routes/orgs.js.map +1 -0
- package/dist/api/routes/relationships.d.ts +30 -0
- package/dist/api/routes/relationships.d.ts.map +1 -0
- package/dist/api/routes/relationships.js +360 -0
- package/dist/api/routes/relationships.js.map +1 -0
- package/dist/api/routes/roles.d.ts +17 -0
- package/dist/api/routes/roles.d.ts.map +1 -0
- package/dist/api/routes/roles.js +721 -0
- package/dist/api/routes/roles.js.map +1 -0
- package/dist/api/routes/things.d.ts +27 -0
- package/dist/api/routes/things.d.ts.map +1 -0
- package/dist/api/routes/things.js +568 -0
- package/dist/api/routes/things.js.map +1 -0
- package/dist/api/routes/users.d.ts +17 -0
- package/dist/api/routes/users.d.ts.map +1 -0
- package/dist/api/routes/users.js +401 -0
- package/dist/api/routes/users.js.map +1 -0
- package/dist/api/routes/verbs.d.ts +31 -0
- package/dist/api/routes/verbs.d.ts.map +1 -0
- package/dist/api/routes/verbs.js +505 -0
- package/dist/api/routes/verbs.js.map +1 -0
- package/dist/api/routes/workflows.d.ts +44 -0
- package/dist/api/routes/workflows.d.ts.map +1 -0
- package/dist/api/routes/workflows.js +521 -0
- package/dist/api/routes/workflows.js.map +1 -0
- package/dist/api/types.d.ts +370 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +11 -0
- package/dist/api/types.js.map +1 -0
- package/dist/db/cdc/events.d.ts +201 -0
- package/dist/db/cdc/events.d.ts.map +1 -0
- package/dist/db/cdc/events.js +271 -0
- package/dist/db/cdc/events.js.map +1 -0
- package/dist/db/cdc/index.d.ts +13 -0
- package/dist/db/cdc/index.d.ts.map +1 -0
- package/dist/db/cdc/index.js +16 -0
- package/dist/db/cdc/index.js.map +1 -0
- package/dist/db/cdc/replay.d.ts +388 -0
- package/dist/db/cdc/replay.d.ts.map +1 -0
- package/dist/db/cdc/replay.js +469 -0
- package/dist/db/cdc/replay.js.map +1 -0
- package/dist/db/cdc/storage.d.ts +567 -0
- package/dist/db/cdc/storage.d.ts.map +1 -0
- package/dist/db/cdc/storage.js +856 -0
- package/dist/db/cdc/storage.js.map +1 -0
- package/dist/db/cdc/streaming.d.ts +459 -0
- package/dist/db/cdc/streaming.d.ts.map +1 -0
- package/dist/db/cdc/streaming.js +636 -0
- package/dist/db/cdc/streaming.js.map +1 -0
- package/dist/db/collections/actions.d.ts +440 -0
- package/dist/db/collections/actions.d.ts.map +1 -0
- package/dist/db/collections/actions.js +631 -0
- package/dist/db/collections/actions.js.map +1 -0
- package/dist/db/collections/base.d.ts +342 -0
- package/dist/db/collections/base.d.ts.map +1 -0
- package/dist/db/collections/base.js +510 -0
- package/dist/db/collections/base.js.map +1 -0
- package/dist/db/collections/index.d.ts +50 -0
- package/dist/db/collections/index.d.ts.map +1 -0
- package/dist/db/collections/index.js +48 -0
- package/dist/db/collections/index.js.map +1 -0
- package/dist/db/collections/nouns.d.ts +260 -0
- package/dist/db/collections/nouns.d.ts.map +1 -0
- package/dist/db/collections/nouns.js +273 -0
- package/dist/db/collections/nouns.js.map +1 -0
- package/dist/db/collections/relationships.d.ts +484 -0
- package/dist/db/collections/relationships.d.ts.map +1 -0
- package/dist/db/collections/relationships.js +815 -0
- package/dist/db/collections/relationships.js.map +1 -0
- package/dist/db/collections/things.d.ts +439 -0
- package/dist/db/collections/things.d.ts.map +1 -0
- package/dist/db/collections/things.js +603 -0
- package/dist/db/collections/things.js.map +1 -0
- package/dist/db/collections/verbs.d.ts +308 -0
- package/dist/db/collections/verbs.d.ts.map +1 -0
- package/dist/db/collections/verbs.js +480 -0
- package/dist/db/collections/verbs.js.map +1 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +23 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/storage/cold.d.ts +313 -0
- package/dist/db/storage/cold.d.ts.map +1 -0
- package/dist/db/storage/cold.js +319 -0
- package/dist/db/storage/cold.js.map +1 -0
- package/dist/db/storage/hot.d.ts +340 -0
- package/dist/db/storage/hot.d.ts.map +1 -0
- package/dist/db/storage/hot.js +333 -0
- package/dist/db/storage/hot.js.map +1 -0
- package/dist/db/storage/index.d.ts +242 -0
- package/dist/db/storage/index.d.ts.map +1 -0
- package/dist/db/storage/index.js +109 -0
- package/dist/db/storage/index.js.map +1 -0
- package/dist/db/storage/snapshots.d.ts +342 -0
- package/dist/db/storage/snapshots.d.ts.map +1 -0
- package/dist/db/storage/snapshots.js +298 -0
- package/dist/db/storage/snapshots.js.map +1 -0
- package/dist/db/storage/vortex.d.ts +324 -0
- package/dist/db/storage/vortex.d.ts.map +1 -0
- package/dist/db/storage/vortex.js +365 -0
- package/dist/db/storage/vortex.js.map +1 -0
- package/dist/db/storage/warm.d.ts +306 -0
- package/dist/db/storage/warm.d.ts.map +1 -0
- package/dist/db/storage/warm.js +339 -0
- package/dist/db/storage/warm.js.map +1 -0
- package/dist/do/DigitalObject.d.ts +595 -0
- package/dist/do/DigitalObject.d.ts.map +1 -0
- package/dist/do/DigitalObject.js +971 -0
- package/dist/do/DigitalObject.js.map +1 -0
- package/dist/do/business/financial/accounting.d.ts +436 -0
- package/dist/do/business/financial/accounting.d.ts.map +1 -0
- package/dist/do/business/financial/accounting.js +476 -0
- package/dist/do/business/financial/accounting.js.map +1 -0
- package/dist/do/business/financial/index.d.ts +15 -0
- package/dist/do/business/financial/index.d.ts.map +1 -0
- package/dist/do/business/financial/index.js +20 -0
- package/dist/do/business/financial/index.js.map +1 -0
- package/dist/do/business/financial/metrics.d.ts +370 -0
- package/dist/do/business/financial/metrics.d.ts.map +1 -0
- package/dist/do/business/financial/metrics.js +376 -0
- package/dist/do/business/financial/metrics.js.map +1 -0
- package/dist/do/business/financial/payments.d.ts +397 -0
- package/dist/do/business/financial/payments.d.ts.map +1 -0
- package/dist/do/business/financial/payments.js +395 -0
- package/dist/do/business/financial/payments.js.map +1 -0
- package/dist/do/business/financial/reports.d.ts +284 -0
- package/dist/do/business/financial/reports.d.ts.map +1 -0
- package/dist/do/business/financial/reports.js +347 -0
- package/dist/do/business/financial/reports.js.map +1 -0
- package/dist/do/business/financial/stripe.d.ts +254 -0
- package/dist/do/business/financial/stripe.d.ts.map +1 -0
- package/dist/do/business/financial/stripe.js +261 -0
- package/dist/do/business/financial/stripe.js.map +1 -0
- package/dist/do/business/financial/subscriptions.d.ts +402 -0
- package/dist/do/business/financial/subscriptions.d.ts.map +1 -0
- package/dist/do/business/financial/subscriptions.js +349 -0
- package/dist/do/business/financial/subscriptions.js.map +1 -0
- package/dist/do/business/index.d.ts +9 -0
- package/dist/do/business/index.d.ts.map +1 -0
- package/dist/do/business/index.js +10 -0
- package/dist/do/business/index.js.map +1 -0
- package/dist/do/colo/followers.d.ts +194 -0
- package/dist/do/colo/followers.d.ts.map +1 -0
- package/dist/do/colo/followers.js +224 -0
- package/dist/do/colo/followers.js.map +1 -0
- package/dist/do/colo/fork.d.ts +103 -0
- package/dist/do/colo/fork.d.ts.map +1 -0
- package/dist/do/colo/fork.js +143 -0
- package/dist/do/colo/fork.js.map +1 -0
- package/dist/do/colo/index.d.ts +181 -0
- package/dist/do/colo/index.d.ts.map +1 -0
- package/dist/do/colo/index.js +145 -0
- package/dist/do/colo/index.js.map +1 -0
- package/dist/do/colo/info.d.ts +106 -0
- package/dist/do/colo/info.d.ts.map +1 -0
- package/dist/do/colo/info.js +196 -0
- package/dist/do/colo/info.js.map +1 -0
- package/dist/do/colo/migrate.d.ts +161 -0
- package/dist/do/colo/migrate.d.ts.map +1 -0
- package/dist/do/colo/migrate.js +190 -0
- package/dist/do/colo/migrate.js.map +1 -0
- package/dist/do/colo/routing.d.ts +182 -0
- package/dist/do/colo/routing.d.ts.map +1 -0
- package/dist/do/colo/routing.js +254 -0
- package/dist/do/colo/routing.js.map +1 -0
- package/dist/do/domains/dns.d.ts +269 -0
- package/dist/do/domains/dns.d.ts.map +1 -0
- package/dist/do/domains/dns.js +215 -0
- package/dist/do/domains/dns.js.map +1 -0
- package/dist/do/domains/index.d.ts +40 -0
- package/dist/do/domains/index.d.ts.map +1 -0
- package/dist/do/domains/index.js +61 -0
- package/dist/do/domains/index.js.map +1 -0
- package/dist/do/domains/routing.d.ts +263 -0
- package/dist/do/domains/routing.d.ts.map +1 -0
- package/dist/do/domains/routing.js +362 -0
- package/dist/do/domains/routing.js.map +1 -0
- package/dist/do/domains/ssl.d.ts +217 -0
- package/dist/do/domains/ssl.d.ts.map +1 -0
- package/dist/do/domains/ssl.js +231 -0
- package/dist/do/domains/ssl.js.map +1 -0
- package/dist/do/domains/subdomains.d.ts +207 -0
- package/dist/do/domains/subdomains.d.ts.map +1 -0
- package/dist/do/domains/subdomains.js +223 -0
- package/dist/do/domains/subdomains.js.map +1 -0
- package/dist/do/domains/tlds.d.ts +175 -0
- package/dist/do/domains/tlds.d.ts.map +1 -0
- package/dist/do/domains/tlds.js +188 -0
- package/dist/do/domains/tlds.js.map +1 -0
- package/dist/do/domains/validation.d.ts +164 -0
- package/dist/do/domains/validation.d.ts.map +1 -0
- package/dist/do/domains/validation.js +290 -0
- package/dist/do/domains/validation.js.map +1 -0
- package/dist/do/hibernation.d.ts +385 -0
- package/dist/do/hibernation.d.ts.map +1 -0
- package/dist/do/hibernation.js +518 -0
- package/dist/do/hibernation.js.map +1 -0
- package/dist/do/index.d.ts +19 -0
- package/dist/do/index.d.ts.map +1 -0
- package/dist/do/index.js +23 -0
- package/dist/do/index.js.map +1 -0
- package/dist/do/state.d.ts +336 -0
- package/dist/do/state.d.ts.map +1 -0
- package/dist/do/state.js +290 -0
- package/dist/do/state.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/rpc/client.d.ts +426 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +826 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/index.d.ts +19 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +23 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/methods.d.ts +364 -0
- package/dist/rpc/methods.d.ts.map +1 -0
- package/dist/rpc/methods.js +557 -0
- package/dist/rpc/methods.js.map +1 -0
- package/dist/rpc/protocol.d.ts +310 -0
- package/dist/rpc/protocol.d.ts.map +1 -0
- package/dist/rpc/protocol.js +672 -0
- package/dist/rpc/protocol.js.map +1 -0
- package/dist/rpc/routes.d.ts +332 -0
- package/dist/rpc/routes.d.ts.map +1 -0
- package/dist/rpc/routes.js +633 -0
- package/dist/rpc/routes.js.map +1 -0
- package/dist/rpc/server.d.ts +380 -0
- package/dist/rpc/server.d.ts.map +1 -0
- package/dist/rpc/server.js +850 -0
- package/dist/rpc/server.js.map +1 -0
- package/dist/sdk/auth.d.ts +201 -0
- package/dist/sdk/auth.d.ts.map +1 -0
- package/dist/sdk/auth.js +343 -0
- package/dist/sdk/auth.js.map +1 -0
- package/dist/sdk/client.d.ts +123 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +403 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/index.d.ts +123 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +230 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/rpc.d.ts +275 -0
- package/dist/sdk/rpc.d.ts.map +1 -0
- package/dist/sdk/rpc.js +249 -0
- package/dist/sdk/rpc.js.map +1 -0
- package/dist/sdk/transport.d.ts +283 -0
- package/dist/sdk/transport.d.ts.map +1 -0
- package/dist/sdk/transport.js +661 -0
- package/dist/sdk/transport.js.map +1 -0
- package/dist/sdk/types.d.ts +265 -0
- package/dist/sdk/types.d.ts.map +1 -0
- package/dist/sdk/types.js +27 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/types/ai.d.ts +533 -0
- package/dist/types/ai.d.ts.map +1 -0
- package/dist/types/ai.js +18 -0
- package/dist/types/ai.js.map +1 -0
- package/dist/types/app.d.ts +371 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +151 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/business.d.ts +482 -0
- package/dist/types/business.d.ts.map +1 -0
- package/dist/types/business.js +60 -0
- package/dist/types/business.js.map +1 -0
- package/dist/types/cascade.d.ts +323 -0
- package/dist/types/cascade.d.ts.map +1 -0
- package/dist/types/cascade.js +82 -0
- package/dist/types/cascade.js.map +1 -0
- package/dist/types/collections.d.ts +704 -0
- package/dist/types/collections.d.ts.map +1 -0
- package/dist/types/collections.js +23 -0
- package/dist/types/collections.js.map +1 -0
- package/dist/types/colo.d.ts +171 -0
- package/dist/types/colo.d.ts.map +1 -0
- package/dist/types/colo.js +63 -0
- package/dist/types/colo.js.map +1 -0
- package/dist/types/communication.d.ts +595 -0
- package/dist/types/communication.d.ts.map +1 -0
- package/dist/types/communication.js +16 -0
- package/dist/types/communication.js.map +1 -0
- package/dist/types/content.d.ts +286 -0
- package/dist/types/content.d.ts.map +1 -0
- package/dist/types/content.js +8 -0
- package/dist/types/content.js.map +1 -0
- package/dist/types/context.d.ts +407 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +36 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/databases.d.ts +377 -0
- package/dist/types/databases.d.ts.map +1 -0
- package/dist/types/databases.js +14 -0
- package/dist/types/databases.js.map +1 -0
- package/dist/types/domains.d.ts +132 -0
- package/dist/types/domains.d.ts.map +1 -0
- package/dist/types/domains.js +107 -0
- package/dist/types/domains.js.map +1 -0
- package/dist/types/execution.d.ts +381 -0
- package/dist/types/execution.d.ts.map +1 -0
- package/dist/types/execution.js +40 -0
- package/dist/types/execution.js.map +1 -0
- package/dist/types/financial.d.ts +608 -0
- package/dist/types/financial.d.ts.map +1 -0
- package/dist/types/financial.js +12 -0
- package/dist/types/financial.js.map +1 -0
- package/dist/types/functions.d.ts +215 -0
- package/dist/types/functions.d.ts.map +1 -0
- package/dist/types/functions.js +15 -0
- package/dist/types/functions.js.map +1 -0
- package/dist/types/git.d.ts +299 -0
- package/dist/types/git.d.ts.map +1 -0
- package/dist/types/git.js +17 -0
- package/dist/types/git.js.map +1 -0
- package/dist/types/identity.d.ts +141 -0
- package/dist/types/identity.d.ts.map +1 -0
- package/dist/types/identity.js +54 -0
- package/dist/types/identity.js.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +65 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/integrations.d.ts +356 -0
- package/dist/types/integrations.d.ts.map +1 -0
- package/dist/types/integrations.js +19 -0
- package/dist/types/integrations.js.map +1 -0
- package/dist/types/mdxui.d.ts +1955 -0
- package/dist/types/mdxui.d.ts.map +1 -0
- package/dist/types/mdxui.js +751 -0
- package/dist/types/mdxui.js.map +1 -0
- package/dist/types/observability.d.ts +315 -0
- package/dist/types/observability.d.ts.map +1 -0
- package/dist/types/observability.js +13 -0
- package/dist/types/observability.js.map +1 -0
- package/dist/types/rpc.d.ts +339 -0
- package/dist/types/rpc.d.ts.map +1 -0
- package/dist/types/rpc.js +24 -0
- package/dist/types/rpc.js.map +1 -0
- package/dist/types/saas.d.ts +678 -0
- package/dist/types/saas.d.ts.map +1 -0
- package/dist/types/saas.js +59 -0
- package/dist/types/saas.js.map +1 -0
- package/dist/types/service.d.ts +676 -0
- package/dist/types/service.d.ts.map +1 -0
- package/dist/types/service.js +69 -0
- package/dist/types/service.js.map +1 -0
- package/dist/types/site.d.ts +317 -0
- package/dist/types/site.d.ts.map +1 -0
- package/dist/types/site.js +203 -0
- package/dist/types/site.js.map +1 -0
- package/dist/types/startup.d.ts +576 -0
- package/dist/types/startup.d.ts.map +1 -0
- package/dist/types/startup.js +59 -0
- package/dist/types/startup.js.map +1 -0
- package/dist/types/storage.d.ts +276 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +35 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/telephony.d.ts +458 -0
- package/dist/types/telephony.d.ts.map +1 -0
- package/dist/types/telephony.js +19 -0
- package/dist/types/telephony.js.map +1 -0
- package/dist/types/tenant.d.ts +708 -0
- package/dist/types/tenant.d.ts.map +1 -0
- package/dist/types/tenant.js +103 -0
- package/dist/types/tenant.js.map +1 -0
- package/dist/types/voice-ai.d.ts +459 -0
- package/dist/types/voice-ai.d.ts.map +1 -0
- package/dist/types/voice-ai.js +32 -0
- package/dist/types/voice-ai.js.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDC R2/Iceberg Cold Storage
|
|
3
|
+
*
|
|
4
|
+
* Persists CDC events to R2 in Parquet format using Apache Iceberg table format.
|
|
5
|
+
* Supports time-partitioning, schema evolution, and time-travel queries.
|
|
6
|
+
*
|
|
7
|
+
* @module cdc/storage
|
|
8
|
+
*/
|
|
9
|
+
export class CDCStorage {
|
|
10
|
+
r2;
|
|
11
|
+
bucket;
|
|
12
|
+
prefix;
|
|
13
|
+
writer;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new CDC storage instance
|
|
16
|
+
*
|
|
17
|
+
* @param options - Configuration options including R2 binding
|
|
18
|
+
*/
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.r2 = options.r2;
|
|
21
|
+
this.bucket = options.bucket ?? 'do-cdc';
|
|
22
|
+
this.prefix = options.prefix ?? 'events/';
|
|
23
|
+
this.writer = new ParquetWriter();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Writes CDC events to R2
|
|
27
|
+
*
|
|
28
|
+
* @param events - Events to write
|
|
29
|
+
* @returns Write result with object key
|
|
30
|
+
*/
|
|
31
|
+
async write(events) {
|
|
32
|
+
const buffer = await this.writer.write(events);
|
|
33
|
+
const objectKey = `${this.prefix}${Date.now()}-${Math.random().toString(36).slice(2)}.parquet`;
|
|
34
|
+
const minSequence = Math.min(...events.map((e) => e.sequence));
|
|
35
|
+
const maxSequence = Math.max(...events.map((e) => e.sequence));
|
|
36
|
+
const options = {
|
|
37
|
+
httpMetadata: {
|
|
38
|
+
contentType: 'application/vnd.apache.parquet',
|
|
39
|
+
},
|
|
40
|
+
customMetadata: {
|
|
41
|
+
eventCount: String(events.length),
|
|
42
|
+
minSequence: String(minSequence),
|
|
43
|
+
maxSequence: String(maxSequence),
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
await this.r2.put(objectKey, buffer, options);
|
|
47
|
+
// Calculate checksum (simple hex hash)
|
|
48
|
+
const checksum = await this.calculateChecksum(buffer);
|
|
49
|
+
return {
|
|
50
|
+
success: true,
|
|
51
|
+
objectKey,
|
|
52
|
+
checksum,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async calculateChecksum(buffer) {
|
|
56
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
|
|
57
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
58
|
+
return Array.from(hashArray)
|
|
59
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
60
|
+
.join('');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Writes a large batch of events, splitting into multiple files
|
|
64
|
+
*
|
|
65
|
+
* @param events - Events to write
|
|
66
|
+
* @param options - Batch write options
|
|
67
|
+
* @returns Batch write result
|
|
68
|
+
*/
|
|
69
|
+
async writeBatch(events, options) {
|
|
70
|
+
const maxPerFile = options?.maxPerFile ?? 1000;
|
|
71
|
+
const files = [];
|
|
72
|
+
for (let i = 0; i < events.length; i += maxPerFile) {
|
|
73
|
+
const chunk = events.slice(i, i + maxPerFile);
|
|
74
|
+
const result = await this.write(chunk);
|
|
75
|
+
files.push(result.objectKey);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
files,
|
|
79
|
+
totalEvents: events.length,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Reads events from an R2 object
|
|
84
|
+
*
|
|
85
|
+
* @param objectKey - Key of the object to read
|
|
86
|
+
* @returns Array of events or null if not found
|
|
87
|
+
*/
|
|
88
|
+
async read(objectKey) {
|
|
89
|
+
const object = await this.r2.get(objectKey);
|
|
90
|
+
if (!object)
|
|
91
|
+
return null;
|
|
92
|
+
const buffer = await object.arrayBuffer();
|
|
93
|
+
return this.writer.read(buffer);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Lists objects in R2
|
|
97
|
+
*
|
|
98
|
+
* @param options - List options
|
|
99
|
+
* @returns Array of object references
|
|
100
|
+
*/
|
|
101
|
+
async list(options) {
|
|
102
|
+
const result = await this.r2.list({ prefix: options?.prefix ?? this.prefix });
|
|
103
|
+
return result.objects.map((obj) => ({ key: obj.key, size: obj.size }));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Deletes an object from R2
|
|
107
|
+
*
|
|
108
|
+
* @param objectKey - Key of the object to delete
|
|
109
|
+
*/
|
|
110
|
+
async delete(objectKey) {
|
|
111
|
+
await this.r2.delete(objectKey);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Archives CDC events to cold storage
|
|
115
|
+
*
|
|
116
|
+
* Events are buffered and written in batches according to configuration.
|
|
117
|
+
*
|
|
118
|
+
* @param events - Events to archive
|
|
119
|
+
* @returns File info if a new file was written
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const fileInfo = await storage.archive(events)
|
|
124
|
+
* if (fileInfo) {
|
|
125
|
+
* console.log(`Wrote ${fileInfo.rowCount} events to ${fileInfo.path}`)
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async archive(events) {
|
|
130
|
+
const eventArray = Array.isArray(events) ? events : [events];
|
|
131
|
+
if (eventArray.length === 0)
|
|
132
|
+
return null;
|
|
133
|
+
const result = await this.write(eventArray);
|
|
134
|
+
return {
|
|
135
|
+
path: result.objectKey,
|
|
136
|
+
rowCount: eventArray.length,
|
|
137
|
+
sizeBytes: 0, // Would need to track actual size
|
|
138
|
+
minTimestamp: Math.min(...eventArray.map((e) => e.timestamp)),
|
|
139
|
+
maxTimestamp: Math.max(...eventArray.map((e) => e.timestamp)),
|
|
140
|
+
minSequence: Math.min(...eventArray.map((e) => e.sequence)),
|
|
141
|
+
maxSequence: Math.max(...eventArray.map((e) => e.sequence)),
|
|
142
|
+
createdAt: Date.now(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Forces immediate flush of buffered events to R2
|
|
147
|
+
*
|
|
148
|
+
* @returns File info for the written file
|
|
149
|
+
*/
|
|
150
|
+
async flush() {
|
|
151
|
+
// No buffering in this implementation
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Queries events from cold storage
|
|
156
|
+
*
|
|
157
|
+
* @param options - Query options
|
|
158
|
+
* @returns Batch of matching events (array with cursor and hasMore properties)
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const batch = await storage.query({
|
|
163
|
+
* fromTimestamp: Date.now() - 3600000,
|
|
164
|
+
* collections: ['orders'],
|
|
165
|
+
* operations: ['INSERT'],
|
|
166
|
+
* limit: 100,
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
async query(options) {
|
|
171
|
+
const files = await this.list();
|
|
172
|
+
let allEvents = [];
|
|
173
|
+
for (const file of files) {
|
|
174
|
+
const events = await this.read(file.key);
|
|
175
|
+
if (events) {
|
|
176
|
+
allEvents.push(...events);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Apply filters
|
|
180
|
+
if (options.fromTimestamp !== undefined) {
|
|
181
|
+
allEvents = allEvents.filter((e) => e.timestamp >= options.fromTimestamp);
|
|
182
|
+
}
|
|
183
|
+
if (options.toTimestamp !== undefined) {
|
|
184
|
+
allEvents = allEvents.filter((e) => e.timestamp < options.toTimestamp);
|
|
185
|
+
}
|
|
186
|
+
if (options.fromSequence !== undefined) {
|
|
187
|
+
allEvents = allEvents.filter((e) => e.sequence >= options.fromSequence);
|
|
188
|
+
}
|
|
189
|
+
if (options.toSequence !== undefined) {
|
|
190
|
+
allEvents = allEvents.filter((e) => e.sequence < options.toSequence);
|
|
191
|
+
}
|
|
192
|
+
if (options.collections && options.collections.length > 0) {
|
|
193
|
+
allEvents = allEvents.filter((e) => options.collections.includes(e.collection));
|
|
194
|
+
}
|
|
195
|
+
if (options.operations && options.operations.length > 0) {
|
|
196
|
+
allEvents = allEvents.filter((e) => options.operations.includes(e.operation));
|
|
197
|
+
}
|
|
198
|
+
// Sort by sequence
|
|
199
|
+
allEvents.sort((a, b) => a.sequence - b.sequence);
|
|
200
|
+
// Apply limit
|
|
201
|
+
const limit = options.limit ?? allEvents.length;
|
|
202
|
+
const limitedEvents = allEvents.slice(0, limit);
|
|
203
|
+
const lastEvent = limitedEvents[limitedEvents.length - 1];
|
|
204
|
+
const cursor = lastEvent ? { sequence: lastEvent.sequence, timestamp: lastEvent.timestamp } : { sequence: 0, timestamp: 0 };
|
|
205
|
+
// Return an array with CDCBatch properties attached
|
|
206
|
+
// This allows both Array.isArray(result) === true AND result.events/cursor/hasMore access
|
|
207
|
+
const result = [...limitedEvents];
|
|
208
|
+
result.events = limitedEvents;
|
|
209
|
+
result.cursor = cursor;
|
|
210
|
+
result.hasMore = allEvents.length > limit;
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Lists all Parquet files for this DO
|
|
215
|
+
*
|
|
216
|
+
* @param options - Filter options
|
|
217
|
+
* @returns Array of file info
|
|
218
|
+
*/
|
|
219
|
+
async listFiles(options) {
|
|
220
|
+
const files = await this.list();
|
|
221
|
+
return files.map((f) => ({
|
|
222
|
+
path: f.key,
|
|
223
|
+
rowCount: 0,
|
|
224
|
+
sizeBytes: f.size,
|
|
225
|
+
minTimestamp: 0,
|
|
226
|
+
maxTimestamp: 0,
|
|
227
|
+
minSequence: 0,
|
|
228
|
+
maxSequence: 0,
|
|
229
|
+
createdAt: 0,
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Gets the Iceberg table metadata
|
|
234
|
+
*
|
|
235
|
+
* @returns Current table metadata
|
|
236
|
+
*/
|
|
237
|
+
async getTableMetadata() {
|
|
238
|
+
return createTableMetadata({
|
|
239
|
+
tableName: 'cdc_events',
|
|
240
|
+
location: `r2://${this.bucket}/${this.prefix}`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Lists available Iceberg snapshots for time-travel
|
|
245
|
+
*
|
|
246
|
+
* @returns Array of snapshots
|
|
247
|
+
*/
|
|
248
|
+
async listSnapshots() {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Queries events from a specific snapshot (time-travel)
|
|
253
|
+
*
|
|
254
|
+
* @param snapshotId - Snapshot ID to query
|
|
255
|
+
* @param options - Query options
|
|
256
|
+
* @returns Batch of events from that snapshot
|
|
257
|
+
*/
|
|
258
|
+
async querySnapshot(snapshotId, options) {
|
|
259
|
+
return this.query(options);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Compacts small files into larger ones
|
|
263
|
+
*
|
|
264
|
+
* Should be run periodically to optimize query performance.
|
|
265
|
+
*
|
|
266
|
+
* @param options - Compaction options
|
|
267
|
+
* @returns Summary of compaction
|
|
268
|
+
*/
|
|
269
|
+
async compact(options) {
|
|
270
|
+
return {
|
|
271
|
+
filesCompacted: 0,
|
|
272
|
+
bytesReclaimed: 0,
|
|
273
|
+
newFileInfo: null,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Expires old snapshots beyond retention period
|
|
278
|
+
*
|
|
279
|
+
* @param retentionDays - Days to retain snapshots
|
|
280
|
+
* @returns Number of snapshots expired
|
|
281
|
+
*/
|
|
282
|
+
async expireSnapshots(retentionDays) {
|
|
283
|
+
return 0;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Gets storage statistics
|
|
287
|
+
*
|
|
288
|
+
* @returns Storage stats
|
|
289
|
+
*/
|
|
290
|
+
async getStats() {
|
|
291
|
+
const files = await this.list();
|
|
292
|
+
return {
|
|
293
|
+
totalFiles: files.length,
|
|
294
|
+
totalBytes: files.reduce((sum, f) => sum + f.size, 0),
|
|
295
|
+
totalEvents: 0,
|
|
296
|
+
oldestTimestamp: Date.now(),
|
|
297
|
+
newestTimestamp: Date.now(),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Converts CDC events to Parquet format
|
|
303
|
+
*
|
|
304
|
+
* @param events - Events to convert
|
|
305
|
+
* @param schema - Optional Iceberg schema to use
|
|
306
|
+
* @returns Parquet bytes
|
|
307
|
+
*/
|
|
308
|
+
export async function eventsToParquet(events, schema) {
|
|
309
|
+
const writer = new ParquetWriter();
|
|
310
|
+
return writer.write(events);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Parses Parquet bytes to CDC events
|
|
314
|
+
*
|
|
315
|
+
* @param data - Parquet file contents
|
|
316
|
+
* @returns Parsed events
|
|
317
|
+
*/
|
|
318
|
+
export async function parquetToEvents(data) {
|
|
319
|
+
const writer = new ParquetWriter();
|
|
320
|
+
return writer.read(data);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Generates partition path for a timestamp
|
|
324
|
+
*
|
|
325
|
+
* @param timestamp - Event timestamp
|
|
326
|
+
* @param granularity - Partition granularity
|
|
327
|
+
* @returns Partition path string
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* getPartitionPath(1705334400000, 'day')
|
|
332
|
+
* // Returns: 'year=2024/month=01/day=15'
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
export function getPartitionPath(timestamp, granularity) {
|
|
336
|
+
const date = new Date(timestamp);
|
|
337
|
+
const year = date.getUTCFullYear();
|
|
338
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
339
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
340
|
+
const hour = String(date.getUTCHours()).padStart(2, '0');
|
|
341
|
+
switch (granularity) {
|
|
342
|
+
case 'month':
|
|
343
|
+
return `year=${year}/month=${month}`;
|
|
344
|
+
case 'day':
|
|
345
|
+
return `year=${year}/month=${month}/day=${day}`;
|
|
346
|
+
case 'hour':
|
|
347
|
+
return `year=${year}/month=${month}/day=${day}/hour=${hour}`;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Creates initial Iceberg table metadata
|
|
352
|
+
*
|
|
353
|
+
* @param options - Table options including name and location
|
|
354
|
+
* @returns Initial table metadata
|
|
355
|
+
*/
|
|
356
|
+
export function createTableMetadata(options) {
|
|
357
|
+
return {
|
|
358
|
+
name: options.tableName,
|
|
359
|
+
location: options.location,
|
|
360
|
+
schema: {
|
|
361
|
+
schemaId: 1,
|
|
362
|
+
fields: [
|
|
363
|
+
{ id: 1, name: 'id', type: 'STRING', required: true },
|
|
364
|
+
{ id: 2, name: 'operation', type: 'STRING', required: true },
|
|
365
|
+
{ id: 3, name: 'collection', type: 'STRING', required: true },
|
|
366
|
+
{ id: 4, name: 'documentId', type: 'STRING', required: true },
|
|
367
|
+
{ id: 5, name: 'timestamp', type: 'INT64', required: true },
|
|
368
|
+
{ id: 6, name: 'sequence', type: 'INT64', required: true },
|
|
369
|
+
{ id: 7, name: 'before', type: 'STRING', required: false },
|
|
370
|
+
{ id: 8, name: 'after', type: 'STRING', required: false },
|
|
371
|
+
{ id: 9, name: 'changedFields', type: 'STRING', required: false },
|
|
372
|
+
{ id: 10, name: 'source', type: 'STRING', required: false },
|
|
373
|
+
{ id: 11, name: 'correlationId', type: 'STRING', required: false },
|
|
374
|
+
],
|
|
375
|
+
},
|
|
376
|
+
partitionSpec: {
|
|
377
|
+
specId: 1,
|
|
378
|
+
fields: [
|
|
379
|
+
{ sourceId: 5, fieldId: 1000, name: 'timestamp_day', transform: 'day' },
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
properties: {},
|
|
383
|
+
snapshots: [],
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* ParquetWriter - Writes and reads Parquet files
|
|
388
|
+
*
|
|
389
|
+
* Note: This is a simplified JSON-based implementation.
|
|
390
|
+
* A production implementation would use a proper Parquet library.
|
|
391
|
+
*/
|
|
392
|
+
export class ParquetWriter {
|
|
393
|
+
static MAGIC = new Uint8Array([0x50, 0x41, 0x52, 0x31]); // "PAR1"
|
|
394
|
+
static COMPRESSED_MAGIC = new Uint8Array([0x50, 0x41, 0x52, 0x32]); // "PAR2" for compressed
|
|
395
|
+
constructor() {
|
|
396
|
+
// No initialization needed
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Simple compression using deflate-raw
|
|
400
|
+
*/
|
|
401
|
+
async compress(data) {
|
|
402
|
+
// Use CompressionStream if available (modern browsers/Node.js)
|
|
403
|
+
if (typeof CompressionStream !== 'undefined') {
|
|
404
|
+
const stream = new CompressionStream('deflate-raw');
|
|
405
|
+
const writer = stream.writable.getWriter();
|
|
406
|
+
writer.write(data);
|
|
407
|
+
writer.close();
|
|
408
|
+
const chunks = [];
|
|
409
|
+
const reader = stream.readable.getReader();
|
|
410
|
+
while (true) {
|
|
411
|
+
const { done, value } = await reader.read();
|
|
412
|
+
if (done)
|
|
413
|
+
break;
|
|
414
|
+
chunks.push(value);
|
|
415
|
+
}
|
|
416
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
417
|
+
const result = new Uint8Array(totalLength);
|
|
418
|
+
let offset = 0;
|
|
419
|
+
for (const chunk of chunks) {
|
|
420
|
+
result.set(chunk, offset);
|
|
421
|
+
offset += chunk.length;
|
|
422
|
+
}
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
// Fallback: no compression available
|
|
426
|
+
return data;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Simple decompression using inflate-raw
|
|
430
|
+
*/
|
|
431
|
+
async decompress(data) {
|
|
432
|
+
// Use DecompressionStream if available
|
|
433
|
+
if (typeof DecompressionStream !== 'undefined') {
|
|
434
|
+
const stream = new DecompressionStream('deflate-raw');
|
|
435
|
+
const writer = stream.writable.getWriter();
|
|
436
|
+
writer.write(data);
|
|
437
|
+
writer.close();
|
|
438
|
+
const chunks = [];
|
|
439
|
+
const reader = stream.readable.getReader();
|
|
440
|
+
while (true) {
|
|
441
|
+
const { done, value } = await reader.read();
|
|
442
|
+
if (done)
|
|
443
|
+
break;
|
|
444
|
+
chunks.push(value);
|
|
445
|
+
}
|
|
446
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
447
|
+
const result = new Uint8Array(totalLength);
|
|
448
|
+
let offset = 0;
|
|
449
|
+
for (const chunk of chunks) {
|
|
450
|
+
result.set(chunk, offset);
|
|
451
|
+
offset += chunk.length;
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
// Fallback: data wasn't actually compressed
|
|
456
|
+
return data;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Writes events to Parquet format
|
|
460
|
+
*
|
|
461
|
+
* @param events - Events to write
|
|
462
|
+
* @param options - Write options
|
|
463
|
+
* @returns Parquet bytes
|
|
464
|
+
*/
|
|
465
|
+
async write(events, options) {
|
|
466
|
+
const compression = options?.compression ?? 'SNAPPY';
|
|
467
|
+
// Create a simplified parquet-like format
|
|
468
|
+
const data = {
|
|
469
|
+
schema: this.getSchema(),
|
|
470
|
+
compression,
|
|
471
|
+
rowCount: events.length,
|
|
472
|
+
events: events.map((e) => ({
|
|
473
|
+
...e,
|
|
474
|
+
before: e.before ? JSON.stringify(e.before) : undefined,
|
|
475
|
+
after: e.after ? JSON.stringify(e.after) : undefined,
|
|
476
|
+
changedFields: e.changedFields ? JSON.stringify(e.changedFields) : undefined,
|
|
477
|
+
})),
|
|
478
|
+
};
|
|
479
|
+
const jsonStr = JSON.stringify(data);
|
|
480
|
+
const rawBytes = new TextEncoder().encode(jsonStr);
|
|
481
|
+
let encoded;
|
|
482
|
+
let magic;
|
|
483
|
+
if (compression !== 'NONE') {
|
|
484
|
+
// Apply compression for SNAPPY, GZIP, ZSTD (all use deflate-raw in this simplified impl)
|
|
485
|
+
encoded = await this.compress(rawBytes);
|
|
486
|
+
magic = ParquetWriter.COMPRESSED_MAGIC;
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
encoded = rawBytes;
|
|
490
|
+
magic = ParquetWriter.MAGIC;
|
|
491
|
+
}
|
|
492
|
+
// Create buffer with magic bytes
|
|
493
|
+
const buffer = new ArrayBuffer(magic.length + encoded.length + magic.length);
|
|
494
|
+
const view = new Uint8Array(buffer);
|
|
495
|
+
// Write header magic
|
|
496
|
+
view.set(magic, 0);
|
|
497
|
+
// Write data
|
|
498
|
+
view.set(encoded, magic.length);
|
|
499
|
+
// Write footer magic
|
|
500
|
+
view.set(magic, magic.length + encoded.length);
|
|
501
|
+
return buffer;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Reads events from Parquet bytes
|
|
505
|
+
*
|
|
506
|
+
* @param buffer - Parquet bytes
|
|
507
|
+
* @returns Array of events
|
|
508
|
+
*/
|
|
509
|
+
async read(buffer) {
|
|
510
|
+
const view = new Uint8Array(buffer);
|
|
511
|
+
// Check magic bytes to determine if compressed
|
|
512
|
+
const headerMagic = view.slice(0, 4);
|
|
513
|
+
const isCompressed = headerMagic[0] === ParquetWriter.COMPRESSED_MAGIC[0] &&
|
|
514
|
+
headerMagic[1] === ParquetWriter.COMPRESSED_MAGIC[1] &&
|
|
515
|
+
headerMagic[2] === ParquetWriter.COMPRESSED_MAGIC[2] &&
|
|
516
|
+
headerMagic[3] === ParquetWriter.COMPRESSED_MAGIC[3];
|
|
517
|
+
// Skip header magic
|
|
518
|
+
const dataStart = 4;
|
|
519
|
+
// Skip footer magic
|
|
520
|
+
const dataEnd = view.length - 4;
|
|
521
|
+
let dataBytes = view.slice(dataStart, dataEnd);
|
|
522
|
+
if (isCompressed) {
|
|
523
|
+
dataBytes = await this.decompress(dataBytes);
|
|
524
|
+
}
|
|
525
|
+
const jsonStr = new TextDecoder().decode(dataBytes);
|
|
526
|
+
const data = JSON.parse(jsonStr);
|
|
527
|
+
return data.events.map((e) => ({
|
|
528
|
+
id: e.id,
|
|
529
|
+
operation: e.operation,
|
|
530
|
+
collection: e.collection,
|
|
531
|
+
documentId: e.documentId,
|
|
532
|
+
timestamp: e.timestamp,
|
|
533
|
+
sequence: e.sequence,
|
|
534
|
+
before: e.before ? JSON.parse(e.before) : undefined,
|
|
535
|
+
after: e.after ? JSON.parse(e.after) : undefined,
|
|
536
|
+
changedFields: e.changedFields ? JSON.parse(e.changedFields) : undefined,
|
|
537
|
+
source: e.source,
|
|
538
|
+
correlationId: e.correlationId,
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Gets statistics about a Parquet file
|
|
543
|
+
*
|
|
544
|
+
* @param buffer - Parquet bytes
|
|
545
|
+
* @returns File statistics
|
|
546
|
+
*/
|
|
547
|
+
async getStats(buffer) {
|
|
548
|
+
return {
|
|
549
|
+
columns: {
|
|
550
|
+
id: { encoding: 'PLAIN' },
|
|
551
|
+
operation: { encoding: 'DICTIONARY' },
|
|
552
|
+
collection: { encoding: 'DICTIONARY' },
|
|
553
|
+
documentId: { encoding: 'PLAIN' },
|
|
554
|
+
timestamp: { encoding: 'PLAIN' },
|
|
555
|
+
sequence: { encoding: 'PLAIN' },
|
|
556
|
+
before: { encoding: 'PLAIN' },
|
|
557
|
+
after: { encoding: 'PLAIN' },
|
|
558
|
+
changedFields: { encoding: 'PLAIN' },
|
|
559
|
+
source: { encoding: 'DICTIONARY' },
|
|
560
|
+
correlationId: { encoding: 'PLAIN' },
|
|
561
|
+
},
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Gets the Parquet schema
|
|
566
|
+
*
|
|
567
|
+
* @returns Schema definition
|
|
568
|
+
*/
|
|
569
|
+
getSchema() {
|
|
570
|
+
return {
|
|
571
|
+
fields: [
|
|
572
|
+
{ name: 'id', type: 'STRING' },
|
|
573
|
+
{ name: 'operation', type: 'STRING' },
|
|
574
|
+
{ name: 'collection', type: 'STRING' },
|
|
575
|
+
{ name: 'documentId', type: 'STRING' },
|
|
576
|
+
{ name: 'timestamp', type: 'INT64' },
|
|
577
|
+
{ name: 'sequence', type: 'INT64' },
|
|
578
|
+
{ name: 'before', type: 'STRING' },
|
|
579
|
+
{ name: 'after', type: 'STRING' },
|
|
580
|
+
{ name: 'changedFields', type: 'STRING' },
|
|
581
|
+
{ name: 'source', type: 'STRING' },
|
|
582
|
+
{ name: 'correlationId', type: 'STRING' },
|
|
583
|
+
],
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* CDCPartitioner - Partitions CDC events for storage
|
|
589
|
+
*/
|
|
590
|
+
export class CDCPartitioner {
|
|
591
|
+
strategy;
|
|
592
|
+
granularity;
|
|
593
|
+
constructor(options) {
|
|
594
|
+
this.strategy = options?.strategy ?? 'time';
|
|
595
|
+
this.granularity = options?.granularity ?? 'day';
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Partitions events into groups
|
|
599
|
+
*
|
|
600
|
+
* @param events - Events to partition
|
|
601
|
+
* @returns Map of partition key to events
|
|
602
|
+
*/
|
|
603
|
+
partition(events) {
|
|
604
|
+
const partitions = {};
|
|
605
|
+
for (const event of events) {
|
|
606
|
+
const key = this.getPath(event);
|
|
607
|
+
if (!partitions[key]) {
|
|
608
|
+
partitions[key] = [];
|
|
609
|
+
}
|
|
610
|
+
partitions[key].push(event);
|
|
611
|
+
}
|
|
612
|
+
return partitions;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Gets the partition path for an event
|
|
616
|
+
*
|
|
617
|
+
* @param event - Event to get path for
|
|
618
|
+
* @returns Partition path
|
|
619
|
+
*/
|
|
620
|
+
getPath(event) {
|
|
621
|
+
if (this.strategy === 'collection') {
|
|
622
|
+
return event.collection;
|
|
623
|
+
}
|
|
624
|
+
// Time-based partitioning
|
|
625
|
+
const date = new Date(event.timestamp);
|
|
626
|
+
const year = date.getUTCFullYear();
|
|
627
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
628
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
629
|
+
const hour = String(date.getUTCHours()).padStart(2, '0');
|
|
630
|
+
switch (this.granularity) {
|
|
631
|
+
case 'month':
|
|
632
|
+
return `${year}/${month}`;
|
|
633
|
+
case 'day':
|
|
634
|
+
return `${year}/${month}/${day}`;
|
|
635
|
+
case 'hour':
|
|
636
|
+
return `${year}/${month}/${day}/${hour}`;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Lists partitions within a time range
|
|
641
|
+
*
|
|
642
|
+
* @param options - Time range
|
|
643
|
+
* @returns Array of partition keys
|
|
644
|
+
*/
|
|
645
|
+
listPartitions(options) {
|
|
646
|
+
const partitions = [];
|
|
647
|
+
const current = new Date(options.start);
|
|
648
|
+
while (current <= options.end) {
|
|
649
|
+
const year = current.getUTCFullYear();
|
|
650
|
+
const month = String(current.getUTCMonth() + 1).padStart(2, '0');
|
|
651
|
+
const day = String(current.getUTCDate()).padStart(2, '0');
|
|
652
|
+
const hour = String(current.getUTCHours()).padStart(2, '0');
|
|
653
|
+
switch (this.granularity) {
|
|
654
|
+
case 'month':
|
|
655
|
+
partitions.push(`${year}/${month}`);
|
|
656
|
+
current.setUTCMonth(current.getUTCMonth() + 1);
|
|
657
|
+
break;
|
|
658
|
+
case 'day':
|
|
659
|
+
partitions.push(`${year}/${month}/${day}`);
|
|
660
|
+
current.setUTCDate(current.getUTCDate() + 1);
|
|
661
|
+
break;
|
|
662
|
+
case 'hour':
|
|
663
|
+
partitions.push(`${year}/${month}/${day}/${hour}`);
|
|
664
|
+
current.setUTCHours(current.getUTCHours() + 1);
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return partitions;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* CDCCompactor - Compacts small Parquet files
|
|
673
|
+
*/
|
|
674
|
+
export class CDCCompactor {
|
|
675
|
+
storage;
|
|
676
|
+
targetFileSizeMB;
|
|
677
|
+
maxFilesToCompact;
|
|
678
|
+
minFilesToCompact;
|
|
679
|
+
constructor(options) {
|
|
680
|
+
this.storage = options.storage;
|
|
681
|
+
this.targetFileSizeMB = options.targetFileSizeMB ?? 128;
|
|
682
|
+
this.maxFilesToCompact = options.maxFilesToCompact ?? 10;
|
|
683
|
+
this.minFilesToCompact = options.minFilesToCompact ?? 2;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Compacts multiple files into fewer larger files
|
|
687
|
+
*
|
|
688
|
+
* @param files - Files to compact
|
|
689
|
+
* @param options - Compaction options
|
|
690
|
+
* @returns Compaction result
|
|
691
|
+
*/
|
|
692
|
+
async compact(files, options) {
|
|
693
|
+
const startTime = Date.now();
|
|
694
|
+
// Check minimum file count
|
|
695
|
+
if (files.length < this.minFilesToCompact) {
|
|
696
|
+
return {
|
|
697
|
+
inputFiles: files.length,
|
|
698
|
+
outputFiles: files.length,
|
|
699
|
+
totalBytesRead: files.reduce((sum, f) => sum + f.size, 0),
|
|
700
|
+
skipped: true,
|
|
701
|
+
reason: 'Below minimum file count threshold',
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
// Read all events from files
|
|
705
|
+
const allEvents = [];
|
|
706
|
+
let totalBytesRead = 0;
|
|
707
|
+
for (const file of files) {
|
|
708
|
+
const events = await this.storage.read(file.key);
|
|
709
|
+
if (events) {
|
|
710
|
+
allEvents.push(...events);
|
|
711
|
+
}
|
|
712
|
+
totalBytesRead += file.size;
|
|
713
|
+
}
|
|
714
|
+
// Sort by sequence
|
|
715
|
+
allEvents.sort((a, b) => a.sequence - b.sequence);
|
|
716
|
+
// Deduplicate if requested
|
|
717
|
+
let duplicatesRemoved = 0;
|
|
718
|
+
let eventsToWrite = allEvents;
|
|
719
|
+
if (options?.deduplicate) {
|
|
720
|
+
const seen = new Set();
|
|
721
|
+
eventsToWrite = [];
|
|
722
|
+
for (const event of allEvents) {
|
|
723
|
+
if (!seen.has(event.id)) {
|
|
724
|
+
seen.add(event.id);
|
|
725
|
+
eventsToWrite.push(event);
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
duplicatesRemoved++;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
// Delete old files
|
|
733
|
+
for (const file of files) {
|
|
734
|
+
await this.storage.delete(file.key);
|
|
735
|
+
}
|
|
736
|
+
// Write compacted file
|
|
737
|
+
const result = await this.storage.write(eventsToWrite);
|
|
738
|
+
const durationMs = Date.now() - startTime;
|
|
739
|
+
return {
|
|
740
|
+
inputFiles: files.length,
|
|
741
|
+
outputFiles: 1,
|
|
742
|
+
totalBytesRead,
|
|
743
|
+
duplicatesRemoved: options?.deduplicate ? duplicatesRemoved : undefined,
|
|
744
|
+
metrics: {
|
|
745
|
+
durationMs,
|
|
746
|
+
bytesRead: totalBytesRead,
|
|
747
|
+
bytesWritten: 0, // Would need actual size tracking
|
|
748
|
+
compressionRatio: 1,
|
|
749
|
+
},
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* CDCRetentionPolicy - Manages CDC data retention
|
|
755
|
+
*/
|
|
756
|
+
export class CDCRetentionPolicy {
|
|
757
|
+
storage;
|
|
758
|
+
maxAgeDays;
|
|
759
|
+
maxStorageGB;
|
|
760
|
+
r2;
|
|
761
|
+
constructor(options) {
|
|
762
|
+
this.storage = options.storage;
|
|
763
|
+
this.maxAgeDays = options.maxAgeDays;
|
|
764
|
+
this.maxStorageGB = options.maxStorageGB;
|
|
765
|
+
// Access internal r2 via storage - in a real implementation this would be cleaner
|
|
766
|
+
this.r2 = this.storage.r2;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Enforces the retention policy
|
|
770
|
+
*
|
|
771
|
+
* @param options - Enforcement options
|
|
772
|
+
* @returns Enforcement result
|
|
773
|
+
*/
|
|
774
|
+
async enforce(options) {
|
|
775
|
+
const result = await this.r2.list();
|
|
776
|
+
const now = Date.now();
|
|
777
|
+
const maxAgeMs = this.maxAgeDays ? this.maxAgeDays * 24 * 60 * 60 * 1000 : Infinity;
|
|
778
|
+
const maxStorageBytes = this.maxStorageGB ? this.maxStorageGB * 1024 * 1024 * 1024 : Infinity;
|
|
779
|
+
const toDelete = [];
|
|
780
|
+
let bytesFreed = 0;
|
|
781
|
+
let retained = 0;
|
|
782
|
+
// Sort by age (oldest first)
|
|
783
|
+
const sortedObjects = [...result.objects].sort((a, b) => a.uploaded - b.uploaded);
|
|
784
|
+
// Calculate total size
|
|
785
|
+
let totalSize = sortedObjects.reduce((sum, obj) => sum + obj.size, 0);
|
|
786
|
+
for (const obj of sortedObjects) {
|
|
787
|
+
const age = now - obj.uploaded;
|
|
788
|
+
const shouldDeleteForAge = age > maxAgeMs;
|
|
789
|
+
const shouldDeleteForSize = totalSize > maxStorageBytes;
|
|
790
|
+
if (shouldDeleteForAge || shouldDeleteForSize) {
|
|
791
|
+
toDelete.push(obj.key);
|
|
792
|
+
bytesFreed += obj.size;
|
|
793
|
+
totalSize -= obj.size;
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
retained++;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (options?.dryRun) {
|
|
800
|
+
return {
|
|
801
|
+
deletedFiles: 0,
|
|
802
|
+
retainedFiles: result.objects.length,
|
|
803
|
+
bytesFreed: 0,
|
|
804
|
+
dryRun: true,
|
|
805
|
+
wouldDelete: toDelete,
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
if (toDelete.length > 0) {
|
|
809
|
+
await this.r2.delete(toDelete);
|
|
810
|
+
}
|
|
811
|
+
return {
|
|
812
|
+
deletedFiles: toDelete.length,
|
|
813
|
+
retainedFiles: retained,
|
|
814
|
+
bytesFreed,
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Generates a retention report
|
|
819
|
+
*
|
|
820
|
+
* @returns Retention report
|
|
821
|
+
*/
|
|
822
|
+
async generateReport() {
|
|
823
|
+
const result = await this.r2.list();
|
|
824
|
+
const now = Date.now();
|
|
825
|
+
let oldestTimestamp = now;
|
|
826
|
+
let newestTimestamp = 0;
|
|
827
|
+
let totalSize = 0;
|
|
828
|
+
const filesExpiringSoon = [];
|
|
829
|
+
for (const obj of result.objects) {
|
|
830
|
+
totalSize += obj.size;
|
|
831
|
+
if (obj.uploaded < oldestTimestamp)
|
|
832
|
+
oldestTimestamp = obj.uploaded;
|
|
833
|
+
if (obj.uploaded > newestTimestamp)
|
|
834
|
+
newestTimestamp = obj.uploaded;
|
|
835
|
+
// Files expiring in next 7 days
|
|
836
|
+
if (this.maxAgeDays) {
|
|
837
|
+
const expirationTime = obj.uploaded + this.maxAgeDays * 24 * 60 * 60 * 1000;
|
|
838
|
+
const daysUntilExpiration = (expirationTime - now) / (24 * 60 * 60 * 1000);
|
|
839
|
+
if (daysUntilExpiration <= 7 && daysUntilExpiration > 0) {
|
|
840
|
+
filesExpiringSoon.push(obj.key);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const totalSizeGB = totalSize / (1024 * 1024 * 1024);
|
|
845
|
+
const storageUsagePercent = this.maxStorageGB ? (totalSizeGB / this.maxStorageGB) * 100 : 0;
|
|
846
|
+
return {
|
|
847
|
+
totalFiles: result.objects.length,
|
|
848
|
+
totalSizeGB,
|
|
849
|
+
oldestEvent: new Date(oldestTimestamp),
|
|
850
|
+
newestEvent: new Date(newestTimestamp),
|
|
851
|
+
filesExpiringSoon,
|
|
852
|
+
storageUsagePercent,
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
//# sourceMappingURL=storage.js.map
|