@happyvertical/smrt-core 0.57.46 → 0.57.47
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/AGENTS.md +11 -3
- package/agents/browser-entry.md +16 -0
- package/agents/build-knowledge.md +58 -14
- package/agents/change-feed.md +20 -0
- package/agents/generators.md +69 -3
- package/agents/schema-paths.md +82 -0
- package/dist/_virtual/_rolldown/runtime.js +22 -1
- package/dist/browser.d.ts +2 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/cascade.d.ts +46 -0
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +96 -7
- package/dist/cascade.js.map +1 -1
- package/dist/change-feed.d.ts.map +1 -1
- package/dist/change-feed.js +7 -4
- package/dist/change-feed.js.map +1 -1
- package/dist/class.d.ts.map +1 -1
- package/dist/class.js +3 -3
- package/dist/class.js.map +1 -1
- package/dist/consumer-plugin/index.d.ts +13 -0
- package/dist/consumer-plugin/index.d.ts.map +1 -1
- package/dist/consumer-plugin/index.js +69 -13
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/consumer-plugin.js +2 -2
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +3 -3
- package/dist/database.js.map +1 -1
- package/dist/dispatch/bus.d.ts.map +1 -1
- package/dist/dispatch/bus.js +1 -4
- package/dist/dispatch/bus.js.map +1 -1
- package/dist/dispatch/index.d.ts +1 -1
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/types.d.ts +22 -3
- package/dist/dispatch/types.d.ts.map +1 -1
- package/dist/generators/changes-route.d.ts.map +1 -1
- package/dist/generators/changes-route.js +2 -2
- package/dist/generators/changes-route.js.map +1 -1
- package/dist/generators/custom-action.d.ts +11 -0
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +23 -4
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lazy-config.d.ts +120 -3
- package/dist/lazy-config.d.ts.map +1 -1
- package/dist/lazy-config.js +81 -10
- package/dist/lazy-config.js.map +1 -1
- package/dist/manifest/generator.d.ts +8 -2
- package/dist/manifest/generator.d.ts.map +1 -1
- package/dist/manifest/generator.js +6 -5
- package/dist/manifest/generator.js.map +1 -1
- package/dist/manifest/index.d.ts +1 -0
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +2 -1
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/local-manifest-reader.d.ts +13 -2
- package/dist/manifest/local-manifest-reader.d.ts.map +1 -1
- package/dist/manifest/local-manifest-reader.js +38 -6
- package/dist/manifest/local-manifest-reader.js.map +1 -1
- package/dist/manifest/manifest-loader.d.ts +9 -8
- package/dist/manifest/manifest-loader.d.ts.map +1 -1
- package/dist/manifest/manifest-loader.js +67 -27
- package/dist/manifest/manifest-loader.js.map +1 -1
- package/dist/manifest/object-declarations.d.ts +116 -0
- package/dist/manifest/object-declarations.d.ts.map +1 -0
- package/dist/manifest/object-declarations.js +161 -0
- package/dist/manifest/object-declarations.js.map +1 -0
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +5 -3
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.d.ts.map +1 -1
- package/dist/manifest/store.js +18 -2
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest/test-artifacts.d.ts +57 -0
- package/dist/manifest/test-artifacts.d.ts.map +1 -0
- package/dist/manifest/test-artifacts.js +111 -0
- package/dist/manifest/test-artifacts.js.map +1 -0
- package/dist/manifest.js +2 -1
- package/dist/manifest.json +5 -3
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +11 -3
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/qualified-name-aliases.d.ts.map +1 -1
- package/dist/migrations/qualified-name-aliases.js +1 -1
- package/dist/migrations/qualified-name-aliases.js.map +1 -1
- package/dist/migrations.js +3 -1
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +2 -2
- package/dist/object.js.map +1 -1
- package/dist/postgres-permissions.d.ts.map +1 -1
- package/dist/postgres-permissions.js +4 -3
- package/dist/postgres-permissions.js.map +1 -1
- package/dist/postgres-timeouts.d.ts +30 -3
- package/dist/postgres-timeouts.d.ts.map +1 -1
- package/dist/postgres-timeouts.js +39 -2
- package/dist/postgres-timeouts.js.map +1 -1
- package/dist/prebuild/index.d.ts.map +1 -1
- package/dist/prebuild/index.js +14 -11
- package/dist/prebuild/index.js.map +1 -1
- package/dist/registry/class-registration.d.ts.map +1 -1
- package/dist/registry/class-registration.js +24 -2
- package/dist/registry/class-registration.js.map +1 -1
- package/dist/registry/collection-exposure.d.ts +27 -0
- package/dist/registry/collection-exposure.d.ts.map +1 -1
- package/dist/registry/collection-exposure.js +74 -1
- package/dist/registry/collection-exposure.js.map +1 -1
- package/dist/registry/collection-resolution.d.ts.map +1 -1
- package/dist/registry/collection-resolution.js +1 -0
- package/dist/registry/collection-resolution.js.map +1 -1
- package/dist/registry/framework-base-classes.d.ts.map +1 -1
- package/dist/registry/framework-base-classes.js +5 -0
- package/dist/registry/framework-base-classes.js.map +1 -1
- package/dist/registry/schema-builder.d.ts +8 -1
- package/dist/registry/schema-builder.d.ts.map +1 -1
- package/dist/registry/schema-builder.js +17 -4
- package/dist/registry/schema-builder.js.map +1 -1
- package/dist/registry/types.d.ts +12 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry.d.ts +2 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +30 -10
- package/dist/registry.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +10 -8
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/scanner/types.d.ts +29 -0
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/schema/generator.d.ts +32 -0
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +59 -0
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/live-parity.d.ts.map +1 -1
- package/dist/schema/live-parity.js +4 -2
- package/dist/schema/live-parity.js.map +1 -1
- package/dist/scripts/browser-unbundled-dev.mjs +90 -0
- package/dist/scripts/generate-test-manifest.js +9 -49
- package/dist/smrt-knowledge.json +16 -16
- package/dist/system/compatibility.d.ts.map +1 -1
- package/dist/system/compatibility.js +12 -4
- package/dist/system/compatibility.js.map +1 -1
- package/dist/system/schema.d.ts +70 -8
- package/dist/system/schema.d.ts.map +1 -1
- package/dist/system/schema.js +231 -24
- package/dist/system/schema.js.map +1 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +14 -2
- package/dist/testing/database.js.map +1 -1
- package/dist/tools/tool-generator.d.ts.map +1 -1
- package/dist/tools/tool-generator.js +2 -2
- package/dist/tools/tool-generator.js.map +1 -1
- package/dist/utils/import-workspace-module.d.ts.map +1 -1
- package/dist/utils/import-workspace-module.js +23 -0
- package/dist/utils/import-workspace-module.js.map +1 -1
- package/dist/utils/naming.js +5 -3
- package/dist/utils/naming.js.map +1 -1
- package/dist/vendor/pluralize/pluralize.js +421 -0
- package/dist/vendor/pluralize/pluralize.js.map +1 -0
- package/dist/vite-plugin/api-client-entries.d.ts +5 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +11 -6
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/consumer-import.d.ts +28 -0
- package/dist/vite-plugin/consumer-import.d.ts.map +1 -0
- package/dist/vite-plugin/consumer-import.js +42 -0
- package/dist/vite-plugin/consumer-import.js.map +1 -0
- package/dist/vite-plugin/dev-plane-route.d.ts +6 -1
- package/dist/vite-plugin/dev-plane-route.d.ts.map +1 -1
- package/dist/vite-plugin/dev-plane-route.js +8 -9
- package/dist/vite-plugin/dev-plane-route.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +12 -9
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/resources-route.d.ts.map +1 -1
- package/dist/vite-plugin/resources-route.js +3 -8
- package/dist/vite-plugin/resources-route.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +7 -11
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/sync-apply-route.d.ts +16 -0
- package/dist/vite-plugin/sync-apply-route.d.ts.map +1 -1
- package/dist/vite-plugin/sync-apply-route.js +48 -6
- package/dist/vite-plugin/sync-apply-route.js.map +1 -1
- package/package.json +12 -12
package/dist/system/schema.js
CHANGED
|
@@ -320,7 +320,7 @@ CREATE TABLE IF NOT EXISTS _smrt_changes_pending (
|
|
|
320
320
|
table_name TEXT NOT NULL,
|
|
321
321
|
row_id TEXT,
|
|
322
322
|
operation TEXT NOT NULL,
|
|
323
|
-
tenant_id
|
|
323
|
+
tenant_id UUID,
|
|
324
324
|
created_at TIMESTAMPTZ NOT NULL
|
|
325
325
|
);
|
|
326
326
|
|
|
@@ -330,7 +330,7 @@ CREATE INDEX IF NOT EXISTS idx_smrt_changes_pending_table
|
|
|
330
330
|
/** Name of the PostgreSQL staging table for deferred change-feed appends. */
|
|
331
331
|
var POSTGRES_CHANGE_FEED_PENDING_TABLE = "_smrt_changes_pending";
|
|
332
332
|
/** PostgreSQL materialization of the portable change-feed table DDL. */
|
|
333
|
-
var CREATE_POSTGRES_SMRT_CHANGES_TABLE = CREATE_SMRT_CHANGES_TABLE.replace(/\bTIMESTAMP\b/g, "TIMESTAMPTZ");
|
|
333
|
+
var CREATE_POSTGRES_SMRT_CHANGES_TABLE = CREATE_SMRT_CHANGES_TABLE.replace(/\bTIMESTAMP\b/g, "TIMESTAMPTZ").replace(/\btenant_id TEXT\b/g, "tenant_id UUID");
|
|
334
334
|
/** PostgreSQL helper used to isolate best-effort feed appends (#2026). */
|
|
335
335
|
var POSTGRES_CHANGE_FEED_APPEND_FUNCTION_NAME = "_smrt_append_change";
|
|
336
336
|
/** PostgreSQL one-statement batch wrapper around the isolated append helper. */
|
|
@@ -350,11 +350,45 @@ var POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION_IDENTITY = `${POSTGRES_CHANGE_FEE
|
|
|
350
350
|
* replaced. Bump it whenever either helper's body changes in a way an existing
|
|
351
351
|
* database must pick up.
|
|
352
352
|
*/
|
|
353
|
-
var POSTGRES_CHANGE_FEED_HELPER_MARKER = "smrt-change-feed-helpers:
|
|
353
|
+
var POSTGRES_CHANGE_FEED_HELPER_MARKER = "smrt-change-feed-helpers:v5";
|
|
354
|
+
/**
|
|
355
|
+
* The previous body marker, still stamped into every v5 body (#3297).
|
|
356
|
+
*
|
|
357
|
+
* v5 only changes how a tenant id is coerced: it is converted to whatever type
|
|
358
|
+
* the live `tenant_id` column has (TEXT before `db:migrate-uuid`, native uuid
|
|
359
|
+
* after), so a v5 body is a drop-in for v4 callers. Older SMRT processes probe
|
|
360
|
+
* for the v4 marker; carrying it stops them from replacing a v5 body with a
|
|
361
|
+
* v4 one (which inserts text into a converted uuid column) during a
|
|
362
|
+
* mixed-version rollout.
|
|
363
|
+
*/
|
|
364
|
+
var POSTGRES_CHANGE_FEED_HELPER_COMPAT_MARKER = "smrt-change-feed-helpers:v4";
|
|
365
|
+
/**
|
|
366
|
+
* Coerce a text tenant id to the live type of `<table>.tenant_id` (#3297).
|
|
367
|
+
*
|
|
368
|
+
* `jsonb_populate_record` builds the table's row type at execution time, so
|
|
369
|
+
* the same body works before and after the column converts to uuid, and a
|
|
370
|
+
* cached plan is invalidated by the ALTER like any other. Empty strings are
|
|
371
|
+
* NULL, matching the TypeScript writers.
|
|
372
|
+
*/
|
|
373
|
+
function postgresTenantIdAs(table, textExpression) {
|
|
374
|
+
return `(jsonb_populate_record(NULL::${table}, jsonb_build_object('tenant_id', NULLIF(${textExpression}, '')))).tenant_id`;
|
|
375
|
+
}
|
|
354
376
|
/** PostgreSQL helper that sequences staged change-feed appends (#2649). */
|
|
355
377
|
var POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME = "_smrt_drain_changes";
|
|
356
|
-
/**
|
|
357
|
-
|
|
378
|
+
/**
|
|
379
|
+
* Exact PostgreSQL identity of the drain helper (#2982): the batch limit plus
|
|
380
|
+
* the live set of sensitive tables, which the drain purges from staging and
|
|
381
|
+
* never sequences.
|
|
382
|
+
*/
|
|
383
|
+
var POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY = `${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME}(integer,text[])`;
|
|
384
|
+
/**
|
|
385
|
+
* Identity of the pre-#2982 single-argument drain, kept as a compatibility
|
|
386
|
+
* entry point so replicas of an older SMRT that still call
|
|
387
|
+
* `_smrt_drain_changes()` keep working during a mixed-version rollout. It
|
|
388
|
+
* delegates to the two-argument drain with no exclusions — exactly the old
|
|
389
|
+
* behavior — because it has no way to know the live sensitive set.
|
|
390
|
+
*/
|
|
391
|
+
var POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION_IDENTITY = `${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME}(integer)`;
|
|
358
392
|
/** How many staged entries one drain call sequences. */
|
|
359
393
|
var POSTGRES_CHANGE_FEED_DRAIN_BATCH = 1e3;
|
|
360
394
|
/**
|
|
@@ -380,10 +414,18 @@ var POSTGRES_CHANGE_FEED_DRAIN_BATCH = 1e3;
|
|
|
380
414
|
* Failures are returned as data, like the append helper, so a drain problem
|
|
381
415
|
* never aborts the caller's transaction. A failed drain leaves the staged rows
|
|
382
416
|
* in place for the next attempt.
|
|
417
|
+
*
|
|
418
|
+
* Sensitive tables (#2982): `p_excluded_tables` is the caller's live
|
|
419
|
+
* sensitive set. Under the drain lock, staged rows for those tables are
|
|
420
|
+
* deleted before any sequence is allocated, and the sequencing batch skips
|
|
421
|
+
* them too, so an entry staged by an older replica (or left over from before
|
|
422
|
+
* an upgrade) never reaches `_smrt_changes`. Neither parameter has a default:
|
|
423
|
+
* a call with no arguments resolves only to the compatibility overload.
|
|
383
424
|
*/
|
|
384
425
|
var CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION = `
|
|
385
426
|
CREATE OR REPLACE FUNCTION ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME}(
|
|
386
|
-
p_limit INTEGER
|
|
427
|
+
p_limit INTEGER,
|
|
428
|
+
p_excluded_tables TEXT[]
|
|
387
429
|
)
|
|
388
430
|
RETURNS TABLE(
|
|
389
431
|
drained_seq BIGINT,
|
|
@@ -398,6 +440,7 @@ LANGUAGE plpgsql
|
|
|
398
440
|
SECURITY INVOKER
|
|
399
441
|
AS $smrt_change_feed_drain$
|
|
400
442
|
-- ${POSTGRES_CHANGE_FEED_HELPER_MARKER}
|
|
443
|
+
-- ${POSTGRES_CHANGE_FEED_HELPER_COMPAT_MARKER}
|
|
401
444
|
DECLARE
|
|
402
445
|
v_base BIGINT;
|
|
403
446
|
v_error_code TEXT;
|
|
@@ -436,6 +479,23 @@ BEGIN
|
|
|
436
479
|
RETURN;
|
|
437
480
|
END IF;
|
|
438
481
|
|
|
482
|
+
-- The feed never records a sensitive table (#2982). Staged entries for
|
|
483
|
+
-- one — from an older replica, or staged before the table was declared
|
|
484
|
+
-- sensitive — are dropped here, before a sequence is allocated.
|
|
485
|
+
-- Bounded like the sequencing batch, so a large legacy backlog cannot make
|
|
486
|
+
-- one pass outlive statement_timeout and stall the feed; the remainder is
|
|
487
|
+
-- purged by later passes, and the batch below skips it meanwhile.
|
|
488
|
+
IF COALESCE(cardinality(p_excluded_tables), 0) > 0 THEN
|
|
489
|
+
DELETE FROM _smrt_changes_pending AS sensitive
|
|
490
|
+
WHERE sensitive.pending_id IN (
|
|
491
|
+
SELECT staged.pending_id
|
|
492
|
+
FROM _smrt_changes_pending AS staged
|
|
493
|
+
WHERE staged.table_name = ANY(p_excluded_tables)
|
|
494
|
+
ORDER BY staged.pending_id
|
|
495
|
+
LIMIT GREATEST(COALESCE(p_limit, ${POSTGRES_CHANGE_FEED_DRAIN_BATCH}), 1)
|
|
496
|
+
);
|
|
497
|
+
END IF;
|
|
498
|
+
|
|
439
499
|
SELECT COALESCE(MAX(changes.seq), 0) INTO v_base FROM _smrt_changes AS changes;
|
|
440
500
|
|
|
441
501
|
RETURN QUERY
|
|
@@ -444,6 +504,11 @@ BEGIN
|
|
|
444
504
|
WHERE pending.pending_id IN (
|
|
445
505
|
SELECT candidate.pending_id
|
|
446
506
|
FROM _smrt_changes_pending AS candidate
|
|
507
|
+
-- A sensitive row committed after the purge above is skipped, not
|
|
508
|
+
-- sequenced; the next drain purges it.
|
|
509
|
+
WHERE NOT (
|
|
510
|
+
candidate.table_name = ANY(COALESCE(p_excluded_tables, ARRAY[]::TEXT[]))
|
|
511
|
+
)
|
|
447
512
|
ORDER BY candidate.pending_id
|
|
448
513
|
LIMIT GREATEST(COALESCE(p_limit, ${POSTGRES_CHANGE_FEED_DRAIN_BATCH}), 1)
|
|
449
514
|
)
|
|
@@ -475,7 +540,7 @@ BEGIN
|
|
|
475
540
|
numbered.table_name,
|
|
476
541
|
numbered.row_id,
|
|
477
542
|
numbered.operation,
|
|
478
|
-
numbered.tenant_id,
|
|
543
|
+
${postgresTenantIdAs("_smrt_changes", "numbered.tenant_id::TEXT")},
|
|
479
544
|
numbered.created_at
|
|
480
545
|
FROM numbered
|
|
481
546
|
RETURNING
|
|
@@ -490,7 +555,7 @@ BEGIN
|
|
|
490
555
|
inserted.table_name,
|
|
491
556
|
inserted.row_id,
|
|
492
557
|
inserted.operation,
|
|
493
|
-
inserted.tenant_id,
|
|
558
|
+
inserted.tenant_id::TEXT,
|
|
494
559
|
NULL::TEXT,
|
|
495
560
|
NULL::TEXT
|
|
496
561
|
FROM inserted
|
|
@@ -512,6 +577,54 @@ END;
|
|
|
512
577
|
$smrt_change_feed_drain$;
|
|
513
578
|
`;
|
|
514
579
|
/**
|
|
580
|
+
* Compatibility single-argument drain (#2982): see
|
|
581
|
+
* {@link POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION_IDENTITY}. Current SMRT
|
|
582
|
+
* never calls it.
|
|
583
|
+
*/
|
|
584
|
+
var CREATE_POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION = `
|
|
585
|
+
CREATE OR REPLACE FUNCTION ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME}(
|
|
586
|
+
p_limit INTEGER DEFAULT ${POSTGRES_CHANGE_FEED_DRAIN_BATCH}
|
|
587
|
+
)
|
|
588
|
+
RETURNS TABLE(
|
|
589
|
+
drained_seq BIGINT,
|
|
590
|
+
drained_table TEXT,
|
|
591
|
+
drained_row_id TEXT,
|
|
592
|
+
drained_operation TEXT,
|
|
593
|
+
drained_tenant_id TEXT,
|
|
594
|
+
error_code TEXT,
|
|
595
|
+
error_message TEXT
|
|
596
|
+
)
|
|
597
|
+
LANGUAGE plpgsql
|
|
598
|
+
SECURITY INVOKER
|
|
599
|
+
AS $smrt_change_feed_drain_compat$
|
|
600
|
+
-- ${POSTGRES_CHANGE_FEED_HELPER_MARKER}
|
|
601
|
+
DECLARE
|
|
602
|
+
v_error_code TEXT;
|
|
603
|
+
v_error_message TEXT;
|
|
604
|
+
BEGIN
|
|
605
|
+
-- Its own boundary, like the drain it delegates to: a resolution or
|
|
606
|
+
-- privilege error on the inner call must come back as data, never abort an
|
|
607
|
+
-- older replica's caller transaction (#2026).
|
|
608
|
+
BEGIN
|
|
609
|
+
RETURN QUERY
|
|
610
|
+
SELECT * FROM ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME}(p_limit, ARRAY[]::TEXT[]);
|
|
611
|
+
EXCEPTION WHEN query_canceled OR assert_failure OR OTHERS THEN
|
|
612
|
+
GET STACKED DIAGNOSTICS
|
|
613
|
+
v_error_code = RETURNED_SQLSTATE,
|
|
614
|
+
v_error_message = MESSAGE_TEXT;
|
|
615
|
+
RETURN QUERY SELECT
|
|
616
|
+
NULL::BIGINT,
|
|
617
|
+
NULL::TEXT,
|
|
618
|
+
NULL::TEXT,
|
|
619
|
+
NULL::TEXT,
|
|
620
|
+
NULL::TEXT,
|
|
621
|
+
v_error_code,
|
|
622
|
+
v_error_message;
|
|
623
|
+
END;
|
|
624
|
+
END;
|
|
625
|
+
$smrt_change_feed_drain_compat$;
|
|
626
|
+
`;
|
|
627
|
+
/**
|
|
515
628
|
* PostgreSQL-only change-feed append function.
|
|
516
629
|
*
|
|
517
630
|
* A PL/pgSQL block with an EXCEPTION handler runs its body in an internal
|
|
@@ -538,6 +651,7 @@ LANGUAGE plpgsql
|
|
|
538
651
|
SECURITY INVOKER
|
|
539
652
|
AS $smrt_change_feed$
|
|
540
653
|
-- ${POSTGRES_CHANGE_FEED_HELPER_MARKER}
|
|
654
|
+
-- ${POSTGRES_CHANGE_FEED_HELPER_COMPAT_MARKER}
|
|
541
655
|
DECLARE
|
|
542
656
|
v_seq BIGINT;
|
|
543
657
|
v_error_code TEXT;
|
|
@@ -590,7 +704,7 @@ BEGIN
|
|
|
590
704
|
p_table_name,
|
|
591
705
|
p_row_id,
|
|
592
706
|
p_operation,
|
|
593
|
-
p_tenant_id,
|
|
707
|
+
${postgresTenantIdAs("_smrt_changes_pending", "p_tenant_id")},
|
|
594
708
|
p_created_at
|
|
595
709
|
);
|
|
596
710
|
|
|
@@ -631,7 +745,7 @@ BEGIN
|
|
|
631
745
|
p_table_name,
|
|
632
746
|
p_row_id,
|
|
633
747
|
p_operation,
|
|
634
|
-
p_tenant_id,
|
|
748
|
+
${postgresTenantIdAs("_smrt_changes", "p_tenant_id")},
|
|
635
749
|
p_created_at
|
|
636
750
|
FROM _smrt_changes AS changes
|
|
637
751
|
RETURNING _smrt_changes.seq INTO v_seq;
|
|
@@ -666,6 +780,7 @@ LANGUAGE plpgsql
|
|
|
666
780
|
SECURITY INVOKER
|
|
667
781
|
AS $smrt_change_feed_batch$
|
|
668
782
|
-- ${POSTGRES_CHANGE_FEED_HELPER_MARKER}
|
|
783
|
+
-- ${POSTGRES_CHANGE_FEED_HELPER_COMPAT_MARKER}
|
|
669
784
|
DECLARE
|
|
670
785
|
v_deferred BOOLEAN;
|
|
671
786
|
v_error_code TEXT;
|
|
@@ -689,7 +804,7 @@ BEGIN
|
|
|
689
804
|
input.value->>'table',
|
|
690
805
|
input.value->>'rowId',
|
|
691
806
|
input.value->>'operation',
|
|
692
|
-
input.value->>'tenantId',
|
|
807
|
+
${postgresTenantIdAs("_smrt_changes_pending", "input.value->>'tenantId'")},
|
|
693
808
|
(input.value->>'timestamp')::TIMESTAMPTZ
|
|
694
809
|
FROM input
|
|
695
810
|
ORDER BY input.entry_index
|
|
@@ -721,7 +836,7 @@ BEGIN
|
|
|
721
836
|
numbered.value->>'table',
|
|
722
837
|
numbered.value->>'rowId',
|
|
723
838
|
numbered.value->>'operation',
|
|
724
|
-
numbered.value->>'tenantId',
|
|
839
|
+
${postgresTenantIdAs("_smrt_changes", "numbered.value->>'tenantId'")},
|
|
725
840
|
(numbered.value->>'timestamp')::TIMESTAMPTZ
|
|
726
841
|
FROM numbered
|
|
727
842
|
ORDER BY numbered.entry_index
|
|
@@ -747,6 +862,54 @@ var POSTGRES_CHANGE_FEED_PENDING_DDL = CREATE_POSTGRES_SMRT_CHANGES_PENDING_TABL
|
|
|
747
862
|
${statement}
|
|
748
863
|
$smrt_change_feed_pending_ddl$;`).join("\n");
|
|
749
864
|
/**
|
|
865
|
+
* Install both drain overloads inside a helper DO block (#2982).
|
|
866
|
+
*
|
|
867
|
+
* The two-argument drain is the first framework routine identity added to
|
|
868
|
+
* databases that already exist, and a new function gets PostgreSQL's default
|
|
869
|
+
* ACL — which a hardened deployment (PUBLIC EXECUTE revoked, the runtime role
|
|
870
|
+
* granted explicitly by the permissions planner) would leave the runtime
|
|
871
|
+
* unable to call. When this block creates it, it therefore inherits the
|
|
872
|
+
* compatibility drain's reconciled EXECUTE grants. A role that may not grant
|
|
873
|
+
* keeps the default ACL; the permissions planner reports and repairs it.
|
|
874
|
+
*/
|
|
875
|
+
var POSTGRES_CHANGE_FEED_DRAIN_INSTALL = ` DECLARE
|
|
876
|
+
v_drain_created BOOLEAN :=
|
|
877
|
+
to_regprocedure('${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY}') IS NULL;
|
|
878
|
+
v_grant RECORD;
|
|
879
|
+
BEGIN
|
|
880
|
+
EXECUTE $smrt_change_feed_drain_ddl$
|
|
881
|
+
${CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION.trim()}
|
|
882
|
+
$smrt_change_feed_drain_ddl$;
|
|
883
|
+
EXECUTE $smrt_change_feed_drain_compat_ddl$
|
|
884
|
+
${CREATE_POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION.trim()}
|
|
885
|
+
$smrt_change_feed_drain_compat_ddl$;
|
|
886
|
+
IF v_drain_created AND (
|
|
887
|
+
SELECT p.proacl FROM pg_proc AS p
|
|
888
|
+
WHERE p.oid = to_regprocedure('${POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION_IDENTITY}')
|
|
889
|
+
) IS NOT NULL THEN
|
|
890
|
+
BEGIN
|
|
891
|
+
EXECUTE 'REVOKE ALL ON FUNCTION ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY} FROM PUBLIC';
|
|
892
|
+
FOR v_grant IN
|
|
893
|
+
SELECT acl.grantee
|
|
894
|
+
FROM pg_proc AS p, aclexplode(p.proacl) AS acl
|
|
895
|
+
WHERE p.oid = to_regprocedure('${POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION_IDENTITY}')
|
|
896
|
+
AND acl.privilege_type = 'EXECUTE'
|
|
897
|
+
LOOP
|
|
898
|
+
IF v_grant.grantee = 0 THEN
|
|
899
|
+
EXECUTE 'GRANT EXECUTE ON FUNCTION ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY} TO PUBLIC';
|
|
900
|
+
ELSE
|
|
901
|
+
EXECUTE format(
|
|
902
|
+
'GRANT EXECUTE ON FUNCTION ${POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY} TO %I',
|
|
903
|
+
pg_get_userbyid(v_grant.grantee)
|
|
904
|
+
);
|
|
905
|
+
END IF;
|
|
906
|
+
END LOOP;
|
|
907
|
+
EXCEPTION WHEN insufficient_privilege THEN
|
|
908
|
+
NULL;
|
|
909
|
+
END;
|
|
910
|
+
END IF;
|
|
911
|
+
END;`;
|
|
912
|
+
/**
|
|
750
913
|
* Serialize PostgreSQL helper replacement inside one server-side statement.
|
|
751
914
|
*
|
|
752
915
|
* The transaction-scoped advisory lock prevents concurrent bootstraps from
|
|
@@ -762,9 +925,7 @@ BEGIN
|
|
|
762
925
|
);
|
|
763
926
|
${POSTGRES_CHANGE_FEED_PENDING_DDL}
|
|
764
927
|
DROP FUNCTION IF EXISTS ${LEGACY_POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY};
|
|
765
|
-
|
|
766
|
-
${CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION.trim()}
|
|
767
|
-
$smrt_change_feed_drain_ddl$;
|
|
928
|
+
${POSTGRES_CHANGE_FEED_DRAIN_INSTALL}
|
|
768
929
|
EXECUTE $smrt_change_feed_ddl$
|
|
769
930
|
${CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION.trim()}
|
|
770
931
|
$smrt_change_feed_ddl$;
|
|
@@ -809,9 +970,7 @@ BEGIN
|
|
|
809
970
|
);
|
|
810
971
|
${POSTGRES_CHANGE_FEED_PENDING_DDL}
|
|
811
972
|
DROP FUNCTION IF EXISTS ${LEGACY_POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY};
|
|
812
|
-
|
|
813
|
-
${CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION.trim()}
|
|
814
|
-
$smrt_change_feed_drain_ddl$;
|
|
973
|
+
${POSTGRES_CHANGE_FEED_DRAIN_INSTALL}
|
|
815
974
|
IF v_append_stale THEN
|
|
816
975
|
EXECUTE $smrt_change_feed_ddl$
|
|
817
976
|
${CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION.trim()}
|
|
@@ -855,9 +1014,7 @@ ${statement}
|
|
|
855
1014
|
$smrt_change_feed_schema_ddl$;`).join("\n")}
|
|
856
1015
|
${POSTGRES_CHANGE_FEED_PENDING_DDL}
|
|
857
1016
|
DROP FUNCTION IF EXISTS ${LEGACY_POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY};
|
|
858
|
-
|
|
859
|
-
${CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION.trim()}
|
|
860
|
-
$smrt_change_feed_drain_ddl$;
|
|
1017
|
+
${POSTGRES_CHANGE_FEED_DRAIN_INSTALL}
|
|
861
1018
|
IF v_append_stale THEN
|
|
862
1019
|
EXECUTE $smrt_change_feed_ddl$
|
|
863
1020
|
${CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION.trim()}
|
|
@@ -986,9 +1143,49 @@ var FRAMEWORK_OPERATIONAL_TABLES = [
|
|
|
986
1143
|
*/
|
|
987
1144
|
var RETIRED_SYSTEM_TABLES = ["_smrt_registry", "_smrt_signals"];
|
|
988
1145
|
/**
|
|
1146
|
+
* System-table columns that hold a real tenant id (#3297): a tenant UUID from
|
|
1147
|
+
* the tenant context, or NULL for global rows. On PostgreSQL they materialize
|
|
1148
|
+
* as native `uuid`, like every application `tenant_id`; other engines keep
|
|
1149
|
+
* TEXT, where `UUID` renders as TEXT anyway. Existing PostgreSQL TEXT columns
|
|
1150
|
+
* convert through `smrt db:migrate-uuid` in a maintenance window.
|
|
1151
|
+
*
|
|
1152
|
+
* Deliberately NOT here (they stay TEXT):
|
|
1153
|
+
* - text identity encodings that are not tenant ids: `_smrt_contexts.owner_id`
|
|
1154
|
+
* (`__collection__` / `__collection__:<tenantId>` scope keys, object/agent
|
|
1155
|
+
* row ids), `_smrt_run_once_claims.actor` (an arbitration namespace),
|
|
1156
|
+
* `_smrt_dispatch.processed_by` (a subscriber name) and
|
|
1157
|
+
* `_smrt_schema_migrations.applied_by` (a hostname);
|
|
1158
|
+
* - `_smrt_run_once_claims.tenant_id`: a NOT NULL claim scope folded into the
|
|
1159
|
+
* claim key; a caller without a tenant must pass a scope string, so it is a
|
|
1160
|
+
* scope key, not a tenant FK;
|
|
1161
|
+
* - `_smrt_ai_usage.tenant_id`: model usage writes tenant UUIDs, but the
|
|
1162
|
+
* published external-agent usage API accepts any non-empty text tenant id,
|
|
1163
|
+
* so converting it is a contract change tracked separately.
|
|
1164
|
+
*/
|
|
1165
|
+
var SYSTEM_TABLE_TENANT_UUID_COLUMNS = Object.freeze([
|
|
1166
|
+
{
|
|
1167
|
+
table: "_smrt_dispatch",
|
|
1168
|
+
column: "tenant_id"
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
table: "_smrt_dispatch_subscriptions",
|
|
1172
|
+
column: "tenant_id"
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
table: "_smrt_changes",
|
|
1176
|
+
column: "tenant_id"
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
table: "_smrt_changes_pending",
|
|
1180
|
+
column: "tenant_id"
|
|
1181
|
+
}
|
|
1182
|
+
]);
|
|
1183
|
+
/**
|
|
989
1184
|
* Materialize the portable system-table schema for a target engine.
|
|
990
1185
|
*
|
|
991
|
-
* PostgreSQL must use TIMESTAMPTZ because every system Date is an instant
|
|
1186
|
+
* PostgreSQL must use TIMESTAMPTZ because every system Date is an instant,
|
|
1187
|
+
* and native UUID for the tenant columns in
|
|
1188
|
+
* {@link SYSTEM_TABLE_TENANT_UUID_COLUMNS} (#3297).
|
|
992
1189
|
* PostgreSQL and DuckDB also materialize integer storage as BIGINT, matching
|
|
993
1190
|
* application-table DDL; SQLite keeps its variable-width INTEGER.
|
|
994
1191
|
*/
|
|
@@ -998,7 +1195,17 @@ function getSystemTableDDL(engine) {
|
|
|
998
1195
|
/** Materialize one portable system-table statement for a target engine. */
|
|
999
1196
|
function getSystemTableDDLForEngine(ddl, engine) {
|
|
1000
1197
|
const integerDdl = engine === "postgres" || engine === "duckdb" || engine === "json" ? ddl.replace(/\bINTEGER\b/g, "BIGINT") : ddl;
|
|
1001
|
-
return engine === "postgres" ? integerDdl.replace(/\bTIMESTAMP\b/g, "TIMESTAMPTZ") : integerDdl;
|
|
1198
|
+
return engine === "postgres" ? toPostgresTenantUuid(integerDdl.replace(/\bTIMESTAMP\b/g, "TIMESTAMPTZ")) : integerDdl;
|
|
1199
|
+
}
|
|
1200
|
+
var POSTGRES_UUID_TENANT_TABLES = new Set(SYSTEM_TABLE_TENANT_UUID_COLUMNS.map(({ table }) => table));
|
|
1201
|
+
/**
|
|
1202
|
+
* Render `tenant_id TEXT` as native uuid on PostgreSQL in the DDL of a table
|
|
1203
|
+
* listed in {@link SYSTEM_TABLE_TENANT_UUID_COLUMNS} (each system DDL
|
|
1204
|
+
* constant creates one table).
|
|
1205
|
+
*/
|
|
1206
|
+
function toPostgresTenantUuid(ddl) {
|
|
1207
|
+
const table = ddl.match(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([A-Za-z_][\w$]*)/i)?.[1];
|
|
1208
|
+
return table && POSTGRES_UUID_TENANT_TABLES.has(table) ? ddl.replace(/\btenant_id TEXT\b/g, "tenant_id UUID") : ddl;
|
|
1002
1209
|
}
|
|
1003
1210
|
/**
|
|
1004
1211
|
* Current SMRT system schema version.
|
|
@@ -1034,6 +1241,6 @@ Object.freeze({
|
|
|
1034
1241
|
"1.11.1": "98112937a3bbb3883c3db1fd5e836751f91a479c1c5da64d4410263a6581ef1f"
|
|
1035
1242
|
});
|
|
1036
1243
|
//#endregion
|
|
1037
|
-
export { ALL_SYSTEM_TABLES, CREATE_POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION, CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION, CREATE_POSTGRES_SMRT_CHANGES_PENDING_TABLE, CREATE_POSTGRES_SMRT_CHANGES_TABLE, CREATE_SMRT_AI_USAGE_TABLE, CREATE_SMRT_BACKFILLS_TABLE, CREATE_SMRT_CHANGES_TABLE, CREATE_SMRT_CONTEXTS_TABLE, CREATE_SMRT_DISPATCH_SUBSCRIPTIONS_TABLE, CREATE_SMRT_DISPATCH_TABLE, CREATE_SMRT_EMBEDDINGS_TABLE, CREATE_SMRT_MIGRATIONS_TABLE, CREATE_SMRT_RUN_ONCE_CLAIMS_TABLE, CREATE_SMRT_SCHEMA_MIGRATIONS_TABLE, ENSURE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, ENSURE_POSTGRES_CHANGE_FEED_SCHEMA, FRAMEWORK_OPERATIONAL_TABLES, LEGACY_POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION_NAME, POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_FUNCTION_NAME, POSTGRES_CHANGE_FEED_DRAIN_BATCH, POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME, POSTGRES_CHANGE_FEED_HELPER_MARKER, POSTGRES_CHANGE_FEED_PENDING_TABLE, REPLACE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, RETIRED_SYSTEM_TABLES, RUN_ONCE_CLAIMS_TABLE, SMRT_SCHEMA_VERSION, getSystemTableDDL, getSystemTableDDLForEngine };
|
|
1244
|
+
export { ALL_SYSTEM_TABLES, CREATE_POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION, CREATE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, CREATE_POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION, CREATE_POSTGRES_CHANGE_FEED_DRAIN_FUNCTION, CREATE_POSTGRES_SMRT_CHANGES_PENDING_TABLE, CREATE_POSTGRES_SMRT_CHANGES_TABLE, CREATE_SMRT_AI_USAGE_TABLE, CREATE_SMRT_BACKFILLS_TABLE, CREATE_SMRT_CHANGES_TABLE, CREATE_SMRT_CONTEXTS_TABLE, CREATE_SMRT_DISPATCH_SUBSCRIPTIONS_TABLE, CREATE_SMRT_DISPATCH_TABLE, CREATE_SMRT_EMBEDDINGS_TABLE, CREATE_SMRT_MIGRATIONS_TABLE, CREATE_SMRT_RUN_ONCE_CLAIMS_TABLE, CREATE_SMRT_SCHEMA_MIGRATIONS_TABLE, ENSURE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, ENSURE_POSTGRES_CHANGE_FEED_SCHEMA, FRAMEWORK_OPERATIONAL_TABLES, LEGACY_POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_BATCH_FUNCTION_NAME, POSTGRES_CHANGE_FEED_APPEND_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_APPEND_FUNCTION_NAME, POSTGRES_CHANGE_FEED_COMPAT_DRAIN_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_DRAIN_BATCH, POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_IDENTITY, POSTGRES_CHANGE_FEED_DRAIN_FUNCTION_NAME, POSTGRES_CHANGE_FEED_HELPER_COMPAT_MARKER, POSTGRES_CHANGE_FEED_HELPER_MARKER, POSTGRES_CHANGE_FEED_PENDING_TABLE, REPLACE_POSTGRES_CHANGE_FEED_APPEND_FUNCTION, RETIRED_SYSTEM_TABLES, RUN_ONCE_CLAIMS_TABLE, SMRT_SCHEMA_VERSION, SYSTEM_TABLE_TENANT_UUID_COLUMNS, getSystemTableDDL, getSystemTableDDLForEngine };
|
|
1038
1245
|
|
|
1039
1246
|
//# sourceMappingURL=schema.js.map
|