@noodleseed/one 0.43.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/billing-read-ops.d.ts.map +1 -1
- package/dist/commands/billing-read-ops.js +11 -10
- package/dist/commands/billing-read-ops.js.map +1 -1
- package/dist/commands/billing-read-view.d.ts +50 -0
- package/dist/commands/billing-read-view.d.ts.map +1 -0
- package/dist/commands/billing-read-view.js +69 -0
- package/dist/commands/billing-read-view.js.map +1 -0
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/protocol/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/protocol/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts +15 -1
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.js +26 -2
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/tool-interaction.d.ts +2 -2
- package/node_modules/@noodle-borg/protocol/dist/tool-interaction.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/ambient-context.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/ambient-context.js +2 -1
- package/node_modules/@noodle-borg/runtime/dist/ambient-context.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/confirmation.d.ts +4 -4
- package/node_modules/@noodle-borg/runtime/dist/confirmation.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/confirmation.js +8 -4
- package/node_modules/@noodle-borg/runtime/dist/confirmation.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +13 -11
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/execute.js +18 -57
- package/node_modules/@noodle-borg/runtime/dist/execute.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts +3 -1
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/index.js +2 -1
- package/node_modules/@noodle-borg/runtime/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/interactive.d.ts +3 -3
- package/node_modules/@noodle-borg/runtime/dist/interactive.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/interactive.js +7 -4
- package/node_modules/@noodle-borg/runtime/dist/interactive.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/result-meta.d.ts +8 -0
- package/node_modules/@noodle-borg/runtime/dist/result-meta.d.ts.map +1 -0
- package/node_modules/@noodle-borg/runtime/dist/result-meta.js +46 -0
- package/node_modules/@noodle-borg/runtime/dist/result-meta.js.map +1 -0
- package/node_modules/@noodle-borg/runtime/dist/result.d.ts +1 -1
- package/node_modules/@noodle-borg/runtime/dist/result.d.ts.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/result.js.map +1 -1
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts +20 -0
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts.map +1 -0
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js +35 -0
- package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-usage.d.ts +21 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-usage.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-usage.js +74 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory-usage.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts +10 -1
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js +110 -0
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/integration.d.ts +13 -0
- package/node_modules/@noodle-borg/service/dist/billing/integration.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/integration.js +20 -0
- package/node_modules/@noodle-borg/service/dist/billing/integration.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.js +6 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js +66 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-usage.d.ts +12 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-usage.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-usage.js +284 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-usage.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/production-footprint.d.ts +20 -0
- package/node_modules/@noodle-borg/service/dist/billing/production-footprint.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/production-footprint.js +24 -0
- package/node_modules/@noodle-borg/service/dist/billing/production-footprint.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/read-contract.d.ts +146 -26
- package/node_modules/@noodle-borg/service/dist/billing/read-contract.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/read-contract.js +64 -18
- package/node_modules/@noodle-borg/service/dist/billing/read-contract.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/shadow-meter.d.ts +20 -0
- package/node_modules/@noodle-borg/service/dist/billing/shadow-meter.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/shadow-meter.js +177 -0
- package/node_modules/@noodle-borg/service/dist/billing/shadow-meter.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-store.d.ts +126 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-store.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-store.js +111 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-store.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-window.d.ts +11 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-window.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-window.js +36 -0
- package/node_modules/@noodle-borg/service/dist/billing/usage-window.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/index.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/index.js +2 -0
- package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/main.js +2 -0
- package/node_modules/@noodle-borg/service/dist/main.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js +6 -0
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/options.d.ts +5 -0
- package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-targets.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-targets.js +2 -0
- package/node_modules/@noodle-borg/service/dist/registry-targets.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/billing-read.d.ts +4 -0
- package/node_modules/@noodle-borg/service/dist/routes/billing-read.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/billing-read.js +111 -10
- package/node_modules/@noodle-borg/service/dist/routes/billing-read.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve.js +10 -1
- package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.js +7 -13
- package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/cloudsql-pool.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/cloudsql-pool.js +4 -1
- package/node_modules/@noodle-borg/service/dist/store/cloudsql-pool.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js +6 -0
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-billing.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-billing.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-billing.js +3 -2
- package/node_modules/@noodle-borg/service/dist/store/postgres-billing.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-rows.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-rows.js +3 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-rows.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts +9 -2
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js +32 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts +1 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.js +6 -6
- package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts +7 -0
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.js +9 -12
- package/node_modules/@noodle-borg/transport-http/dist/handler.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.d.ts +3 -0
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.d.ts.map +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.js +13 -0
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.js.map +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/tool-dispatch.d.ts +27 -0
- package/node_modules/@noodle-borg/transport-http/dist/tool-dispatch.d.ts.map +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/tool-dispatch.js +35 -0
- package/node_modules/@noodle-borg/transport-http/dist/tool-dispatch.js.map +1 -0
- package/package.json +1 -1
|
@@ -129,6 +129,72 @@ export async function ensureBillingSchema(pool) {
|
|
|
129
129
|
await pool.query(`
|
|
130
130
|
CREATE INDEX IF NOT EXISTS org_billing_links_billing_account_org_idx
|
|
131
131
|
ON org_billing_links (billing_account_id, org_slug)
|
|
132
|
+
`);
|
|
133
|
+
await pool.query(`
|
|
134
|
+
CREATE TABLE IF NOT EXISTS billing_usage_observation_state (
|
|
135
|
+
singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
|
|
136
|
+
started_at timestamptz NOT NULL
|
|
137
|
+
)
|
|
138
|
+
`);
|
|
139
|
+
await pool.query(`
|
|
140
|
+
CREATE TABLE IF NOT EXISTS billing_usage_events (
|
|
141
|
+
event_id text PRIMARY KEY,
|
|
142
|
+
mode text NOT NULL CHECK (mode = 'shadow'),
|
|
143
|
+
high_confidence_key_hash bytea,
|
|
144
|
+
fallback_fingerprint bytea NOT NULL,
|
|
145
|
+
semantic_fingerprint bytea NOT NULL,
|
|
146
|
+
billing_account_id text NOT NULL REFERENCES billing_accounts(id) ON DELETE RESTRICT,
|
|
147
|
+
org_slug text NOT NULL,
|
|
148
|
+
app_slug text NOT NULL,
|
|
149
|
+
environment text NOT NULL,
|
|
150
|
+
deployment_id text NOT NULL,
|
|
151
|
+
link_version integer NOT NULL CHECK (link_version > 0),
|
|
152
|
+
snapshot_id text NOT NULL,
|
|
153
|
+
snapshot_version integer NOT NULL CHECK (snapshot_version > 0),
|
|
154
|
+
admitted_at timestamptz NOT NULL,
|
|
155
|
+
window_start timestamptz NOT NULL,
|
|
156
|
+
window_end timestamptz NOT NULL CHECK (window_end > window_start),
|
|
157
|
+
recorded_at timestamptz NOT NULL,
|
|
158
|
+
CHECK (high_confidence_key_hash IS NULL OR octet_length(high_confidence_key_hash) = 32),
|
|
159
|
+
CHECK (octet_length(fallback_fingerprint) = 32),
|
|
160
|
+
CHECK (octet_length(semantic_fingerprint) = 32),
|
|
161
|
+
FOREIGN KEY (billing_account_id, snapshot_id)
|
|
162
|
+
REFERENCES billing_entitlement_snapshots(billing_account_id, id) ON DELETE RESTRICT
|
|
163
|
+
)
|
|
164
|
+
`);
|
|
165
|
+
await pool.query(`
|
|
166
|
+
CREATE UNIQUE INDEX IF NOT EXISTS billing_usage_events_high_confidence_key_idx
|
|
167
|
+
ON billing_usage_events (high_confidence_key_hash)
|
|
168
|
+
WHERE high_confidence_key_hash IS NOT NULL
|
|
169
|
+
`);
|
|
170
|
+
await pool.query(`
|
|
171
|
+
CREATE INDEX IF NOT EXISTS billing_usage_events_fallback_retry_idx
|
|
172
|
+
ON billing_usage_events (fallback_fingerprint, semantic_fingerprint, recorded_at DESC)
|
|
173
|
+
`);
|
|
174
|
+
await pool.query(`
|
|
175
|
+
CREATE TABLE IF NOT EXISTS billing_usage_account_windows (
|
|
176
|
+
billing_account_id text NOT NULL REFERENCES billing_accounts(id) ON DELETE RESTRICT,
|
|
177
|
+
window_start timestamptz NOT NULL,
|
|
178
|
+
window_end timestamptz NOT NULL CHECK (window_end > window_start),
|
|
179
|
+
observed_calls bigint NOT NULL CHECK (observed_calls >= 0),
|
|
180
|
+
first_admitted_at timestamptz NOT NULL,
|
|
181
|
+
last_admitted_at timestamptz NOT NULL,
|
|
182
|
+
updated_at timestamptz NOT NULL,
|
|
183
|
+
PRIMARY KEY (billing_account_id, window_start)
|
|
184
|
+
)
|
|
185
|
+
`);
|
|
186
|
+
await pool.query(`
|
|
187
|
+
CREATE TABLE IF NOT EXISTS billing_usage_org_windows (
|
|
188
|
+
billing_account_id text NOT NULL REFERENCES billing_accounts(id) ON DELETE RESTRICT,
|
|
189
|
+
org_slug text NOT NULL,
|
|
190
|
+
window_start timestamptz NOT NULL,
|
|
191
|
+
window_end timestamptz NOT NULL CHECK (window_end > window_start),
|
|
192
|
+
observed_calls bigint NOT NULL CHECK (observed_calls >= 0),
|
|
193
|
+
first_admitted_at timestamptz NOT NULL,
|
|
194
|
+
last_admitted_at timestamptz NOT NULL,
|
|
195
|
+
updated_at timestamptz NOT NULL,
|
|
196
|
+
PRIMARY KEY (billing_account_id, org_slug, window_start)
|
|
197
|
+
)
|
|
132
198
|
`);
|
|
133
199
|
await pool.query(`
|
|
134
200
|
CREATE TABLE IF NOT EXISTS billing_legacy_migration_preparations (
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-schema.js","sourceRoot":"","sources":["../../src/billing/postgres-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAuB,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpF,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAU;IAClD,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;GAUhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;GAqBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;GAkBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;GAehB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;GAiBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;GAYhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;GAShB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;GAShB,CAAC,CAAC;IAEH,MAAM,IAAI,CAAC,KAAK,CACd;;;iCAG6B,EAC7B;QACE,iBAAiB,CAAC,EAAE;QACpB,iBAAiB,CAAC,QAAQ;QAC1B,iBAAiB,CAAC,OAAO;QACzB,iBAAiB,CAAC,aAAa;QAC/B,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,YAAY,CAAC;QAC9C,iBAAiB,CAAC,eAAe;QACjC,iBAAiB,CAAC,SAAS;KAC5B,CACF,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAC/B,mDAAmD,EACnD,CAAC,iBAAiB,CAAC,EAAE,CAAC,CACvB,CAAC;IACF,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,IACE,aAAa,KAAK,SAAS;QAC3B,aAAa,CAAC,eAAe,KAAK,iBAAiB,CAAC,eAAe,EACnE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"postgres-schema.js","sourceRoot":"","sources":["../../src/billing/postgres-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAuB,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpF,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAU;IAClD,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;GAUhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;GAqBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;GAkBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;GAOhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;GAehB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;GAKhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;GAIhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;GAYhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;GAiBhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;GAYhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;GAGhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;GAShB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;GAShB,CAAC,CAAC;IAEH,MAAM,IAAI,CAAC,KAAK,CACd;;;iCAG6B,EAC7B;QACE,iBAAiB,CAAC,EAAE;QACpB,iBAAiB,CAAC,QAAQ;QAC1B,iBAAiB,CAAC,OAAO;QACzB,iBAAiB,CAAC,aAAa;QAC/B,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,YAAY,CAAC;QAC9C,iBAAiB,CAAC,eAAe;QACjC,iBAAiB,CAAC,SAAS;KAC5B,CACF,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAC/B,mDAAmD,EACnD,CAAC,iBAAiB,CAAC,EAAE,CAAC,CACvB,CAAC;IACF,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,IACE,aAAa,KAAK,SAAS;QAC3B,aAAa,CAAC,eAAe,KAAK,iBAAiB,CAAC,eAAe,EACnE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
2
|
+
import type { BillingUsageRead, BillingUsageReceipt, GetBillingAccountUsageInput, GetOrganizationBillingUsageInput, RecordBillingUsageInput } from './usage-store.js';
|
|
3
|
+
export declare function recordBillingUsageRow(pool: Pool, input: RecordBillingUsageInput, options: {
|
|
4
|
+
readonly now: () => Date;
|
|
5
|
+
readonly retryWindowMs: number;
|
|
6
|
+
}): Promise<BillingUsageReceipt>;
|
|
7
|
+
export declare function startBillingUsageObservationRow(pool: Pool, input: {
|
|
8
|
+
readonly startedAt: string;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
export declare function getBillingAccountUsageRow(pool: Pool, input: GetBillingAccountUsageInput): Promise<BillingUsageRead>;
|
|
11
|
+
export declare function getOrganizationBillingUsageRow(pool: Pool, input: GetOrganizationBillingUsageInput): Promise<BillingUsageRead>;
|
|
12
|
+
//# sourceMappingURL=postgres-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-usage.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-usage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,IAAI,CAAC;AAG3C,OAAO,KAAK,EAEV,gBAAgB,EAChB,mBAAmB,EACnB,2BAA2B,EAC3B,gCAAgC,EAEhC,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAyC1B,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,uBAAuB,EAC9B,OAAO,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACpE,OAAO,CAAC,mBAAmB,CAAC,CAU9B;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,IAAI,EACV,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpC,OAAO,CAAC,MAAM,CAAC,CAQjB;AAoHD,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAkC3B;AAED,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,gCAAgC,GACtC,OAAO,CAAC,gBAAgB,CAAC,CAwC3B"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { validateSlug } from '../store/validate.js';
|
|
3
|
+
import { validateBillingAccountId } from './model.js';
|
|
4
|
+
import { BillingUsageIdempotencyConflictError, billingAccountUsageScope, buildBillingUsageRead, normalizeBillingUsageReadInput, normalizeRecordBillingUsageInput, organizationUsageScope, validateBillingUsageRetryWindowMs, } from './usage-store.js';
|
|
5
|
+
import { normalizeBillingUsageInstant, resolveUtcMonthlyUsageWindow } from './usage-window.js';
|
|
6
|
+
const SHADOW_LOCK_TIMEOUT_MS = 150;
|
|
7
|
+
const SHADOW_STATEMENT_TIMEOUT_MS = 200;
|
|
8
|
+
export function recordBillingUsageRow(pool, input, options) {
|
|
9
|
+
const usage = normalizeRecordBillingUsageInput(input);
|
|
10
|
+
const retryWindowMs = validateBillingUsageRetryWindowMs(options.retryWindowMs);
|
|
11
|
+
const recordedAt = normalizeBillingUsageInstant('billing usage recorded at', options.now().toISOString());
|
|
12
|
+
return withUsageTransaction(pool, (client) => recordBillingUsageTx(client, { usage, retryWindowMs, recordedAt }));
|
|
13
|
+
}
|
|
14
|
+
export function startBillingUsageObservationRow(pool, input) {
|
|
15
|
+
const startedAt = normalizeBillingUsageInstant('billing usage observation start', input.startedAt);
|
|
16
|
+
return withUsageTransaction(pool, (client) => getOrStartBillingUsageObservation(client, startedAt));
|
|
17
|
+
}
|
|
18
|
+
async function recordBillingUsageTx(client, input) {
|
|
19
|
+
if (input.usage.highConfidenceKeyHash !== undefined) {
|
|
20
|
+
await lockUsageDedupeKey(client, `exact:${input.usage.highConfidenceKeyHash}`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await lockUsageDedupeKey(client, `fallback:${input.usage.fallbackFingerprint}`);
|
|
24
|
+
}
|
|
25
|
+
if (input.usage.highConfidenceKeyHash !== undefined) {
|
|
26
|
+
const exact = await client.query(`SELECT * FROM billing_usage_events
|
|
27
|
+
WHERE high_confidence_key_hash = decode($1, 'hex')`, [input.usage.highConfidenceKeyHash]);
|
|
28
|
+
if (exact.rows[0] !== undefined) {
|
|
29
|
+
if (!exact.rows[0].semantic_fingerprint.equals(Buffer.from(input.usage.semanticFingerprint, 'hex'))) {
|
|
30
|
+
throw new BillingUsageIdempotencyConflictError();
|
|
31
|
+
}
|
|
32
|
+
return eventReceipt(exact.rows[0], 'duplicate', 'high_confidence_key');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (input.usage.highConfidenceKeyHash === undefined) {
|
|
36
|
+
const retryCutoff = new Date(Date.parse(input.recordedAt) - input.retryWindowMs).toISOString();
|
|
37
|
+
const retryCeiling = new Date(Date.parse(input.recordedAt) + input.retryWindowMs).toISOString();
|
|
38
|
+
const fallback = await client.query(`SELECT *
|
|
39
|
+
FROM billing_usage_events
|
|
40
|
+
WHERE fallback_fingerprint = decode($1, 'hex')
|
|
41
|
+
AND semantic_fingerprint = decode($2, 'hex')
|
|
42
|
+
AND recorded_at >= $3
|
|
43
|
+
AND recorded_at <= $4
|
|
44
|
+
ORDER BY recorded_at DESC, event_id
|
|
45
|
+
LIMIT 1`, [input.usage.fallbackFingerprint, input.usage.semanticFingerprint, retryCutoff, retryCeiling]);
|
|
46
|
+
if (fallback.rows[0] !== undefined) {
|
|
47
|
+
return eventReceipt(fallback.rows[0], 'duplicate', 'bounded_fallback');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const resolution = await client.query(`SELECT links.billing_account_id,
|
|
51
|
+
links.version AS link_version,
|
|
52
|
+
snapshot.id AS snapshot_id,
|
|
53
|
+
snapshot.version AS snapshot_version,
|
|
54
|
+
snapshot.monthly_usage_anchor
|
|
55
|
+
FROM org_billing_links AS links
|
|
56
|
+
JOIN billing_account_active_snapshots AS active
|
|
57
|
+
ON active.billing_account_id = links.billing_account_id
|
|
58
|
+
JOIN billing_entitlement_snapshots AS snapshot
|
|
59
|
+
ON snapshot.billing_account_id = active.billing_account_id
|
|
60
|
+
AND snapshot.id = active.snapshot_id
|
|
61
|
+
WHERE links.org_slug = $1
|
|
62
|
+
AND links.active
|
|
63
|
+
AND snapshot.verification_status = 'verified'
|
|
64
|
+
FOR UPDATE OF links, active, snapshot`, [input.usage.org]);
|
|
65
|
+
const resolved = resolution.rows[0];
|
|
66
|
+
if (resolved === undefined)
|
|
67
|
+
throw new Error('billing setup is incomplete for organization');
|
|
68
|
+
const window = resolveUtcMonthlyUsageWindow(toIsoString(resolved.monthly_usage_anchor), input.usage.admittedAt);
|
|
69
|
+
const eventId = `bue_${randomUUID()}`;
|
|
70
|
+
const inserted = await client.query(`INSERT INTO billing_usage_events
|
|
71
|
+
(event_id, mode, high_confidence_key_hash, fallback_fingerprint, semantic_fingerprint,
|
|
72
|
+
billing_account_id, org_slug, app_slug, environment, deployment_id, link_version,
|
|
73
|
+
snapshot_id, snapshot_version, admitted_at, window_start, window_end, recorded_at)
|
|
74
|
+
VALUES ($1, 'shadow', decode($2, 'hex'), decode($3, 'hex'), decode($4, 'hex'),
|
|
75
|
+
$5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
|
76
|
+
RETURNING *`, [
|
|
77
|
+
eventId,
|
|
78
|
+
input.usage.highConfidenceKeyHash ?? null,
|
|
79
|
+
input.usage.fallbackFingerprint,
|
|
80
|
+
input.usage.semanticFingerprint,
|
|
81
|
+
resolved.billing_account_id,
|
|
82
|
+
input.usage.org,
|
|
83
|
+
input.usage.app,
|
|
84
|
+
input.usage.environment,
|
|
85
|
+
input.usage.deploymentId,
|
|
86
|
+
resolved.link_version,
|
|
87
|
+
resolved.snapshot_id,
|
|
88
|
+
resolved.snapshot_version,
|
|
89
|
+
input.usage.admittedAt,
|
|
90
|
+
window.start,
|
|
91
|
+
window.end,
|
|
92
|
+
input.recordedAt,
|
|
93
|
+
]);
|
|
94
|
+
const attribution = eventRowAttribution(inserted.rows[0]);
|
|
95
|
+
await incrementAccountAggregate(client, attribution, input.recordedAt);
|
|
96
|
+
await incrementOrganizationAggregate(client, attribution, input.recordedAt);
|
|
97
|
+
return {
|
|
98
|
+
eventId,
|
|
99
|
+
outcome: 'recorded',
|
|
100
|
+
deduplicatedBy: null,
|
|
101
|
+
attribution,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export async function getBillingAccountUsageRow(pool, input) {
|
|
105
|
+
const scope = billingAccountUsageScope(input.billingAccountId);
|
|
106
|
+
const read = normalizeBillingUsageReadInput({
|
|
107
|
+
at: input.at,
|
|
108
|
+
observedSince: await getBillingUsageObservationStart(pool),
|
|
109
|
+
});
|
|
110
|
+
const snapshot = await pool.query(`SELECT snapshot.monthly_usage_anchor
|
|
111
|
+
FROM billing_account_active_snapshots AS active
|
|
112
|
+
JOIN billing_entitlement_snapshots AS snapshot
|
|
113
|
+
ON snapshot.billing_account_id = active.billing_account_id
|
|
114
|
+
AND snapshot.id = active.snapshot_id
|
|
115
|
+
WHERE active.billing_account_id = $1
|
|
116
|
+
AND snapshot.verification_status = 'verified'`, [scope.billingAccountId]);
|
|
117
|
+
const anchor = snapshot.rows[0]?.monthly_usage_anchor;
|
|
118
|
+
if (anchor === undefined) {
|
|
119
|
+
return buildBillingUsageRead({ scope, monthlyUsageAnchor: undefined, ...read });
|
|
120
|
+
}
|
|
121
|
+
const monthlyUsageAnchor = toIsoString(anchor);
|
|
122
|
+
const window = resolveUtcMonthlyUsageWindow(monthlyUsageAnchor, read.at);
|
|
123
|
+
const aggregate = await pool.query(`SELECT observed_calls::text
|
|
124
|
+
FROM billing_usage_account_windows
|
|
125
|
+
WHERE billing_account_id = $1 AND window_start = $2`, [scope.billingAccountId, window.start]);
|
|
126
|
+
return buildBillingUsageRead({
|
|
127
|
+
scope,
|
|
128
|
+
monthlyUsageAnchor,
|
|
129
|
+
...read,
|
|
130
|
+
observedCalls: parseObservedCalls(aggregate.rows[0]?.observed_calls),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
export async function getOrganizationBillingUsageRow(pool, input) {
|
|
134
|
+
const scope = organizationUsageScope(input.org);
|
|
135
|
+
const read = normalizeBillingUsageReadInput({
|
|
136
|
+
at: input.at,
|
|
137
|
+
observedSince: await getBillingUsageObservationStart(pool),
|
|
138
|
+
});
|
|
139
|
+
const resolution = await pool.query(`SELECT links.billing_account_id, snapshot.monthly_usage_anchor
|
|
140
|
+
FROM org_billing_links AS links
|
|
141
|
+
JOIN billing_account_active_snapshots AS active
|
|
142
|
+
ON active.billing_account_id = links.billing_account_id
|
|
143
|
+
JOIN billing_entitlement_snapshots AS snapshot
|
|
144
|
+
ON snapshot.billing_account_id = active.billing_account_id
|
|
145
|
+
AND snapshot.id = active.snapshot_id
|
|
146
|
+
WHERE links.org_slug = $1
|
|
147
|
+
AND links.active
|
|
148
|
+
AND snapshot.verification_status = 'verified'`, [scope.org]);
|
|
149
|
+
const resolved = resolution.rows[0];
|
|
150
|
+
if (resolved === undefined) {
|
|
151
|
+
return buildBillingUsageRead({ scope, monthlyUsageAnchor: undefined, ...read });
|
|
152
|
+
}
|
|
153
|
+
const monthlyUsageAnchor = toIsoString(resolved.monthly_usage_anchor);
|
|
154
|
+
const window = resolveUtcMonthlyUsageWindow(monthlyUsageAnchor, read.at);
|
|
155
|
+
const aggregate = await pool.query(`SELECT observed_calls::text
|
|
156
|
+
FROM billing_usage_org_windows
|
|
157
|
+
WHERE billing_account_id = $1 AND org_slug = $2 AND window_start = $3`, [resolved.billing_account_id, scope.org, window.start]);
|
|
158
|
+
return buildBillingUsageRead({
|
|
159
|
+
scope,
|
|
160
|
+
monthlyUsageAnchor,
|
|
161
|
+
...read,
|
|
162
|
+
observedCalls: parseObservedCalls(aggregate.rows[0]?.observed_calls),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function incrementAccountAggregate(client, attribution, updatedAt) {
|
|
166
|
+
const result = await client.query(`INSERT INTO billing_usage_account_windows
|
|
167
|
+
(billing_account_id, window_start, window_end, observed_calls,
|
|
168
|
+
first_admitted_at, last_admitted_at, updated_at)
|
|
169
|
+
VALUES ($1, $2, $3, 1, $4, $4, $5)
|
|
170
|
+
ON CONFLICT (billing_account_id, window_start) DO UPDATE SET
|
|
171
|
+
observed_calls = billing_usage_account_windows.observed_calls + 1,
|
|
172
|
+
first_admitted_at = LEAST(billing_usage_account_windows.first_admitted_at, EXCLUDED.first_admitted_at),
|
|
173
|
+
last_admitted_at = GREATEST(billing_usage_account_windows.last_admitted_at, EXCLUDED.last_admitted_at),
|
|
174
|
+
updated_at = EXCLUDED.updated_at
|
|
175
|
+
WHERE billing_usage_account_windows.window_end = EXCLUDED.window_end`, [
|
|
176
|
+
attribution.billingAccountId,
|
|
177
|
+
attribution.windowStart,
|
|
178
|
+
attribution.windowEnd,
|
|
179
|
+
attribution.admittedAt,
|
|
180
|
+
updatedAt,
|
|
181
|
+
]);
|
|
182
|
+
if (result.rowCount !== 1)
|
|
183
|
+
throw new Error('billing usage window anchor changed unexpectedly');
|
|
184
|
+
}
|
|
185
|
+
async function incrementOrganizationAggregate(client, attribution, updatedAt) {
|
|
186
|
+
const result = await client.query(`INSERT INTO billing_usage_org_windows
|
|
187
|
+
(billing_account_id, org_slug, window_start, window_end, observed_calls,
|
|
188
|
+
first_admitted_at, last_admitted_at, updated_at)
|
|
189
|
+
VALUES ($1, $2, $3, $4, 1, $5, $5, $6)
|
|
190
|
+
ON CONFLICT (billing_account_id, org_slug, window_start) DO UPDATE SET
|
|
191
|
+
observed_calls = billing_usage_org_windows.observed_calls + 1,
|
|
192
|
+
first_admitted_at = LEAST(billing_usage_org_windows.first_admitted_at, EXCLUDED.first_admitted_at),
|
|
193
|
+
last_admitted_at = GREATEST(billing_usage_org_windows.last_admitted_at, EXCLUDED.last_admitted_at),
|
|
194
|
+
updated_at = EXCLUDED.updated_at
|
|
195
|
+
WHERE billing_usage_org_windows.window_end = EXCLUDED.window_end`, [
|
|
196
|
+
attribution.billingAccountId,
|
|
197
|
+
attribution.org,
|
|
198
|
+
attribution.windowStart,
|
|
199
|
+
attribution.windowEnd,
|
|
200
|
+
attribution.admittedAt,
|
|
201
|
+
updatedAt,
|
|
202
|
+
]);
|
|
203
|
+
if (result.rowCount !== 1)
|
|
204
|
+
throw new Error('billing usage window anchor changed unexpectedly');
|
|
205
|
+
}
|
|
206
|
+
async function lockUsageDedupeKey(client, key) {
|
|
207
|
+
await client.query('SELECT pg_advisory_xact_lock(hashtextextended($1, 0))', [
|
|
208
|
+
`billing-usage:${key}`,
|
|
209
|
+
]);
|
|
210
|
+
}
|
|
211
|
+
function eventReceipt(row, outcome, deduplicatedBy) {
|
|
212
|
+
return {
|
|
213
|
+
eventId: row.event_id,
|
|
214
|
+
outcome,
|
|
215
|
+
deduplicatedBy,
|
|
216
|
+
attribution: eventRowAttribution(row),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function eventRowAttribution(row) {
|
|
220
|
+
return {
|
|
221
|
+
billingAccountId: validateBillingAccountId(row.billing_account_id),
|
|
222
|
+
org: validateSlug('org', row.org_slug),
|
|
223
|
+
app: validateSlug('app', row.app_slug),
|
|
224
|
+
environment: validateSlug('env', row.environment),
|
|
225
|
+
deploymentId: row.deployment_id,
|
|
226
|
+
linkVersion: row.link_version,
|
|
227
|
+
snapshotId: row.snapshot_id,
|
|
228
|
+
snapshotVersion: row.snapshot_version,
|
|
229
|
+
admittedAt: toIsoString(row.admitted_at),
|
|
230
|
+
windowStart: toIsoString(row.window_start),
|
|
231
|
+
windowEnd: toIsoString(row.window_end),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function parseObservedCalls(value) {
|
|
235
|
+
if (value === undefined)
|
|
236
|
+
return 0;
|
|
237
|
+
const parsed = Number(value);
|
|
238
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
239
|
+
throw new Error('persisted billing usage exceeds the supported reporting range');
|
|
240
|
+
}
|
|
241
|
+
return parsed;
|
|
242
|
+
}
|
|
243
|
+
async function getOrStartBillingUsageObservation(query, startedAt) {
|
|
244
|
+
await query.query(`INSERT INTO billing_usage_observation_state (singleton, started_at)
|
|
245
|
+
VALUES (true, $1)
|
|
246
|
+
ON CONFLICT (singleton) DO NOTHING`, [startedAt]);
|
|
247
|
+
const result = await query.query('SELECT started_at FROM billing_usage_observation_state WHERE singleton = true');
|
|
248
|
+
const persistedStartedAt = result.rows[0]?.started_at;
|
|
249
|
+
if (persistedStartedAt === undefined) {
|
|
250
|
+
throw new Error('billing usage observation failed to initialize');
|
|
251
|
+
}
|
|
252
|
+
return toIsoString(persistedStartedAt);
|
|
253
|
+
}
|
|
254
|
+
async function getBillingUsageObservationStart(query) {
|
|
255
|
+
const result = await query.query('SELECT started_at FROM billing_usage_observation_state WHERE singleton = true');
|
|
256
|
+
const startedAt = result.rows[0]?.started_at;
|
|
257
|
+
if (startedAt === undefined)
|
|
258
|
+
throw new Error('billing usage observation has not started');
|
|
259
|
+
return toIsoString(startedAt);
|
|
260
|
+
}
|
|
261
|
+
function toIsoString(value) {
|
|
262
|
+
return normalizeBillingUsageInstant('persisted billing usage timestamp', value instanceof Date ? value.toISOString() : value);
|
|
263
|
+
}
|
|
264
|
+
async function withUsageTransaction(pool, operation) {
|
|
265
|
+
const client = await pool.connect();
|
|
266
|
+
try {
|
|
267
|
+
await client.query('BEGIN');
|
|
268
|
+
try {
|
|
269
|
+
await client.query(`SELECT set_config('lock_timeout', $1, true),
|
|
270
|
+
set_config('statement_timeout', $2, true)`, [`${SHADOW_LOCK_TIMEOUT_MS}ms`, `${SHADOW_STATEMENT_TIMEOUT_MS}ms`]);
|
|
271
|
+
const result = await operation(client);
|
|
272
|
+
await client.query('COMMIT');
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
await client.query('ROLLBACK');
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
client.release();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=postgres-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-usage.js","sourceRoot":"","sources":["../../src/billing/postgres-usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ServerRegistry } from '../registry.js';
|
|
2
|
+
export interface ActiveHostedAppFootprint {
|
|
3
|
+
/** Distinct active logical apps across every organization in this projection. */
|
|
4
|
+
readonly active: number;
|
|
5
|
+
/** Organization-attributed counts; never an account identity or cross-org app inventory. */
|
|
6
|
+
readonly byOrganization: Readonly<Record<string, number>>;
|
|
7
|
+
}
|
|
8
|
+
type HostedAppInventory = Pick<ServerRegistry, 'listApps'>;
|
|
9
|
+
/**
|
|
10
|
+
* Derive the current production footprint from canonical hosted deployment state.
|
|
11
|
+
*
|
|
12
|
+
* Every registry app is served by the Noodle cloud data plane. An app consumes one slot when any
|
|
13
|
+
* deployment is active; environments, versions, revisions, routes, and replicas stay folded into
|
|
14
|
+
* that one {@link AppSummary}-shaped registry row. This is deliberately a read projection rather
|
|
15
|
+
* than another mutable counter, so archive, restore, activation, and organization relinks cannot
|
|
16
|
+
* drift from the deployment system of record.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readActiveHostedAppFootprint(registry: HostedAppInventory, organizations: readonly string[]): Promise<ActiveHostedAppFootprint>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=production-footprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-footprint.d.ts","sourceRoot":"","sources":["../../src/billing/production-footprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3D;AAED,KAAK,kBAAkB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CAiBnC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the current production footprint from canonical hosted deployment state.
|
|
3
|
+
*
|
|
4
|
+
* Every registry app is served by the Noodle cloud data plane. An app consumes one slot when any
|
|
5
|
+
* deployment is active; environments, versions, revisions, routes, and replicas stay folded into
|
|
6
|
+
* that one {@link AppSummary}-shaped registry row. This is deliberately a read projection rather
|
|
7
|
+
* than another mutable counter, so archive, restore, activation, and organization relinks cannot
|
|
8
|
+
* drift from the deployment system of record.
|
|
9
|
+
*/
|
|
10
|
+
export async function readActiveHostedAppFootprint(registry, organizations) {
|
|
11
|
+
const byOrganization = {};
|
|
12
|
+
let active = 0;
|
|
13
|
+
for (const org of new Set(organizations)) {
|
|
14
|
+
const inventory = await registry.listApps(org, { limit: Number.MAX_SAFE_INTEGER });
|
|
15
|
+
if (inventory.truncated) {
|
|
16
|
+
throw new Error(`active hosted app inventory was truncated for organization "${org}"`);
|
|
17
|
+
}
|
|
18
|
+
const orgActive = inventory.apps.filter((app) => app.active && app.archivedAt === undefined).length;
|
|
19
|
+
byOrganization[org] = orgActive;
|
|
20
|
+
active += orgActive;
|
|
21
|
+
}
|
|
22
|
+
return { active, byOrganization };
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=production-footprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-footprint.js","sourceRoot":"","sources":["../../src/billing/production-footprint.ts"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,QAA4B,EAC5B,aAAgC;IAEhC,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,MAAM,GAAG,IAAI,IAAI,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;QACnF,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,+DAA+D,GAAG,GAAG,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CACrC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,CACpD,CAAC,MAAM,CAAC;QACT,cAAc,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;AACpC,CAAC"}
|