primitive-admin 1.1.0-alpha.74 → 1.1.0-alpha.76
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/bin/primitive.js +110 -21
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/collection-type-configs.js +1 -1
- package/dist/src/commands/collection-type-configs.js.map +1 -1
- package/dist/src/commands/config.js +8 -4
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/database-type-configs.js +1 -1
- package/dist/src/commands/database-type-configs.js.map +1 -1
- package/dist/src/commands/databases.js +25 -31
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +9 -24
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/env.d.ts +1 -1
- package/dist/src/commands/env.js +14 -11
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/functions.js +173 -4
- package/dist/src/commands/functions.js.map +1 -1
- package/dist/src/commands/groups.js +1 -1
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/init.d.ts +12 -15
- package/dist/src/commands/init.js +36 -77
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/prompts.js +54 -39
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.js +1 -1
- package/dist/src/commands/rule-sets.js.map +1 -1
- package/dist/src/commands/scripts.js +17 -4
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/sync-app-settings.js +2 -4
- package/dist/src/commands/sync-app-settings.js.map +1 -1
- package/dist/src/commands/sync.d.ts +41 -2
- package/dist/src/commands/sync.js +635 -364
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/workflows.js +62 -31
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +23 -2
- package/dist/src/lib/api-client.js +24 -5
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-match-guard.d.ts +44 -0
- package/dist/src/lib/app-match-guard.js +72 -0
- package/dist/src/lib/app-match-guard.js.map +1 -0
- package/dist/src/lib/block-selector.d.ts +58 -0
- package/dist/src/lib/block-selector.js +92 -0
- package/dist/src/lib/block-selector.js.map +1 -0
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +11 -8
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +108 -54
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
- package/dist/src/lib/config-object-descriptor.js +1 -3
- package/dist/src/lib/config-object-descriptor.js.map +1 -1
- package/dist/src/lib/config.d.ts +2 -2
- package/dist/src/lib/config.js +2 -2
- package/dist/src/lib/credentials-store.d.ts +3 -3
- package/dist/src/lib/credentials-store.js +3 -3
- package/dist/src/lib/credentials-store.js.map +1 -1
- package/dist/src/lib/document-export-permissions.d.ts +30 -0
- package/dist/src/lib/document-export-permissions.js +54 -0
- package/dist/src/lib/document-export-permissions.js.map +1 -0
- package/dist/src/lib/env-resolver-core.d.ts +41 -9
- package/dist/src/lib/env-resolver-core.js +84 -13
- package/dist/src/lib/env-resolver-core.js.map +1 -1
- package/dist/src/lib/env-resolver.d.ts +3 -3
- package/dist/src/lib/env-resolver.js +2 -2
- package/dist/src/lib/function-bundle.d.ts +11 -1
- package/dist/src/lib/function-bundle.js +13 -1
- package/dist/src/lib/function-bundle.js.map +1 -1
- package/dist/src/lib/function-collect.d.ts +123 -0
- package/dist/src/lib/function-collect.js +463 -0
- package/dist/src/lib/function-collect.js.map +1 -0
- package/dist/src/lib/function-db-types.d.ts +149 -0
- package/dist/src/lib/function-db-types.js +587 -0
- package/dist/src/lib/function-db-types.js.map +1 -0
- package/dist/src/lib/function-grants-preflight.d.ts +64 -0
- package/dist/src/lib/function-grants-preflight.js +100 -0
- package/dist/src/lib/function-grants-preflight.js.map +1 -0
- package/dist/src/lib/function-sync.d.ts +23 -0
- package/dist/src/lib/function-sync.js +65 -1
- package/dist/src/lib/function-sync.js.map +1 -1
- package/dist/src/lib/function-triggers.d.ts +6 -0
- package/dist/src/lib/function-triggers.js +63 -4
- package/dist/src/lib/function-triggers.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +340 -0
- package/dist/src/lib/generated-config-surfaces.js +669 -17
- package/dist/src/lib/generated-config-surfaces.js.map +1 -1
- package/dist/src/lib/generated-sdk-types.d.ts +12 -0
- package/dist/src/lib/generated-sdk-types.js +13 -0
- package/dist/src/lib/generated-sdk-types.js.map +1 -0
- package/dist/src/lib/init-adopt.js +2 -2
- package/dist/src/lib/init-adopt.js.map +1 -1
- package/dist/src/lib/init-assets.js +3 -3
- package/dist/src/lib/init-config.d.ts +1 -1
- package/dist/src/lib/init-ios-links.js +1 -1
- package/dist/src/lib/init-ios-links.js.map +1 -1
- package/dist/src/lib/init-plan.d.ts +1 -1
- package/dist/src/lib/init-plan.js +1 -1
- package/dist/src/lib/init-xcode.d.ts +2 -2
- package/dist/src/lib/init-xcode.js +6 -5
- package/dist/src/lib/init-xcode.js.map +1 -1
- package/dist/src/lib/local-state.d.ts +1 -1
- package/dist/src/lib/local-state.js +1 -1
- package/dist/src/lib/local-test-cases.d.ts +1 -1
- package/dist/src/lib/local-test-cases.js +2 -1
- package/dist/src/lib/local-test-cases.js.map +1 -1
- package/dist/src/lib/migration-nag.d.ts +2 -2
- package/dist/src/lib/migration-nag.js +4 -3
- package/dist/src/lib/migration-nag.js.map +1 -1
- package/dist/src/lib/project-config.d.ts +23 -20
- package/dist/src/lib/project-config.js +27 -45
- package/dist/src/lib/project-config.js.map +1 -1
- package/dist/src/lib/snapshots.d.ts +2 -2
- package/dist/src/lib/snapshots.js +2 -2
- package/dist/src/lib/swift-codegen/generator.d.ts +1 -1
- package/dist/src/lib/swift-codegen/generator.js +1 -1
- package/dist/src/lib/sync-dir-selector.d.ts +1 -1
- package/dist/src/lib/sync-dir-selector.js +1 -1
- package/dist/src/lib/sync-paths.d.ts +52 -16
- package/dist/src/lib/sync-paths.js +68 -22
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/sync-resource-types.d.ts +2 -2
- package/dist/src/lib/sync-resource-types.js +2 -2
- package/dist/src/lib/template.d.ts +2 -2
- package/dist/src/lib/template.js +2 -2
- package/dist/src/lib/test-case-keys.d.ts +1 -1
- package/dist/src/lib/test-case-keys.js +1 -1
- package/dist/src/lib/toml-database-config.js +19 -2
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/workflow-codegen/generator.d.ts +1 -1
- package/dist/src/lib/workflow-codegen/generator.js +1 -1
- package/package.json +3 -3
|
@@ -578,6 +578,346 @@ export interface RetiredConfigKey {
|
|
|
578
578
|
export declare const RETIRED_CONFIG_KEYS: Record<string, Record<string, RetiredConfigKey>>;
|
|
579
579
|
/** The retired-key entry for `key` under `prefix`, or null when it is simply unknown. */
|
|
580
580
|
export declare function retiredConfigKey(prefix: string, key: string): RetiredConfigKey | null;
|
|
581
|
+
/**
|
|
582
|
+
* The capability grammar for server functions — #3182 phase 1, rewritten by
|
|
583
|
+
* #3279 (project `server-functions` phase 3).
|
|
584
|
+
*
|
|
585
|
+
* A function declares in its own TOML what it may CONFIGURE:
|
|
586
|
+
*
|
|
587
|
+
* capabilities = ["integration:stripe", "secret:STRIPE_KEY", "databases:delete"]
|
|
588
|
+
*
|
|
589
|
+
* ── Why the grammar is this small ────────────────────────────────────────
|
|
590
|
+
*
|
|
591
|
+
* The intent's decision (2026-09-09, "Authorization inside a function?"):
|
|
592
|
+
* function code acts as the system. The invocation gate is the authorization,
|
|
593
|
+
* and inside a function every platform call carries the app's own authority in
|
|
594
|
+
* every family. A capability is therefore never a statement about DATA — a
|
|
595
|
+
* model, a prompt, a channel, a member — because the function may reach all of
|
|
596
|
+
* it. It is declared only where it configures something:
|
|
597
|
+
*
|
|
598
|
+
* `integration:<key>` the egress allowlist — which upstream hosts the
|
|
599
|
+
* function's outbound calls may reach;
|
|
600
|
+
* `secret:<NAME>` credential least privilege — which secret VALUES may
|
|
601
|
+
* cross into the sandbox at all;
|
|
602
|
+
* the high-blast list {@link HIGH_BLAST_CAPABILITIES} — the operations
|
|
603
|
+
* whose blast radius the intent keeps opt-in.
|
|
604
|
+
*
|
|
605
|
+
* Every other string a function used to declare is RETIRED, and the grammar
|
|
606
|
+
* says so by name: an author who still writes `database:orders/Order:read`
|
|
607
|
+
* is told the model changed and what stays, not "unknown family", which would
|
|
608
|
+
* send them to check their spelling.
|
|
609
|
+
*
|
|
610
|
+
* ── Why the components have a charset ────────────────────────────────────
|
|
611
|
+
*
|
|
612
|
+
* A keyed grant's key must match `[A-Za-z0-9_-]+`, so neither `:` nor `/` can
|
|
613
|
+
* enter a component and the string is INJECTIVE — one string, one object. An
|
|
614
|
+
* integration or secret whose key carries a delimiter is simply unreachable
|
|
615
|
+
* from functions, with an error that says why (D3182-001's argument, kept).
|
|
616
|
+
*
|
|
617
|
+
* ── Why this module is pure ──────────────────────────────────────────────
|
|
618
|
+
*
|
|
619
|
+
* Capabilities are validated twice — by `config push`'s preflight, so an
|
|
620
|
+
* author sees the error against their own file, and by the server, which is
|
|
621
|
+
* authoritative because the raw admin API exists. Two enforcement points must
|
|
622
|
+
* not be two grammars, so the grammar lives here, in the dependency-free
|
|
623
|
+
* `src/config-surface/` tree the CLI vendors at build time
|
|
624
|
+
* (`cli/scripts/gen-config-surfaces.mjs`). The server imports this module; the
|
|
625
|
+
* CLI imports the generated copy; the drift guard fails if they differ.
|
|
626
|
+
*/
|
|
627
|
+
/** Every component of a grant. Injectivity depends on this. */
|
|
628
|
+
export declare const GRANT_COMPONENT_PATTERN: RegExp;
|
|
629
|
+
/** `ServerFunctionConfig.capabilities` is a StringSet with these bounds. */
|
|
630
|
+
export declare const MAX_CAPABILITY_ENTRIES = 100;
|
|
631
|
+
export declare const MAX_CAPABILITY_ENTRY_LENGTH = 200;
|
|
632
|
+
/**
|
|
633
|
+
* The two keyed families the intent keeps: one component under
|
|
634
|
+
* {@link GRANT_COMPONENT_PATTERN}, naming a single object. Every key format the
|
|
635
|
+
* platform issues fits: an integration key is `^[a-z0-9][a-z0-9-_]{2,}$` and a
|
|
636
|
+
* secret name is `^[A-Z][A-Z0-9_]{0,63}$`.
|
|
637
|
+
*/
|
|
638
|
+
export declare const KEYED_GRANT_FAMILIES: readonly ["integration", "secret"];
|
|
639
|
+
/**
|
|
640
|
+
* The high-blast-radius opt-ins — #3279, criterion 5 (CR3279-001, D3279-003).
|
|
641
|
+
*
|
|
642
|
+
* Since function code acts as the system, admission to a family is no longer
|
|
643
|
+
* an authority statement: everything the gateway lets through runs with the
|
|
644
|
+
* app's own authority. Most operations are fine that way — that is the whole
|
|
645
|
+
* decision. A short list is not, and the intent names its categories: delete a
|
|
646
|
+
* database, app or user; role changes; secret changes; resource provisioning.
|
|
647
|
+
* Those stay opt-in, so a function that can do them says so in a reviewable
|
|
648
|
+
* line of its TOML.
|
|
649
|
+
*
|
|
650
|
+
* The strings are EXACT and 1:1 with the operation id, so there is nothing to
|
|
651
|
+
* look up: `users.setRole` needs `users:setRole`. They parse with the verb as
|
|
652
|
+
* their KEY, because two exact capabilities in one family must not cover each
|
|
653
|
+
* other — `databases:create` is not permission to delete a database.
|
|
654
|
+
*
|
|
655
|
+
* The database ROLE mutations are here because they hand out persistent
|
|
656
|
+
* authority: a group grant assigns the manager role (D3279-003). App deletion
|
|
657
|
+
* and secret writes have no app-API route today; they are recorded, not gated,
|
|
658
|
+
* and the profile generator refuses to admit a future such route without a row
|
|
659
|
+
* here (`HIGH_BLAST_WATCH` in `scripts/lib/function-profile.mjs`).
|
|
660
|
+
*/
|
|
661
|
+
export declare const HIGH_BLAST_CAPABILITIES: readonly ["databases:create", "databases:delete", "databases:transferOwnership", "databases:addManager", "databases:revokePermission", "databases:grantGroupPermission", "databases:revokeGroupPermission", "users:remove", "users:setRole", "blobBuckets:createBucket", "blobBuckets:deleteBucket"];
|
|
662
|
+
/** The exact strings, which since #3279 are exactly the high-blast list. */
|
|
663
|
+
export declare const EXACT_GRANT_STRINGS: readonly ["databases:create", "databases:delete", "databases:transferOwnership", "databases:addManager", "databases:revokePermission", "databases:grantGroupPermission", "databases:revokeGroupPermission", "users:remove", "users:setRole", "blobBuckets:createBucket", "blobBuckets:deleteBucket"];
|
|
664
|
+
export type GrantFamily = (typeof KEYED_GRANT_FAMILIES)[number] | "databases" | "users" | "blobBuckets";
|
|
665
|
+
/**
|
|
666
|
+
* The retired FAMILIES (#3279), each with the reason it is gone.
|
|
667
|
+
*
|
|
668
|
+
* The value is what the family used to authorize, phrased as what a function
|
|
669
|
+
* now reaches without it. A refusal names the authored string, says it is
|
|
670
|
+
* retired, gives this reason, tells the author to delete the entry, and lists
|
|
671
|
+
* what stays.
|
|
672
|
+
*/
|
|
673
|
+
export declare const RETIRED_GRANT_FAMILIES: Record<string, string>;
|
|
674
|
+
/** The retired EXACT strings (#3279), on the same terms. */
|
|
675
|
+
export declare const RETIRED_GRANT_STRINGS: Record<string, string>;
|
|
676
|
+
/**
|
|
677
|
+
* The retirement sentence for one authored string, or null when the string is
|
|
678
|
+
* not a retired one.
|
|
679
|
+
*
|
|
680
|
+
* Exported so the enforcement-time reader (`loadConfigGrants`) can tell a
|
|
681
|
+
* retired string on a pre-change row — tolerated, logged — from a string that
|
|
682
|
+
* was never a grant at all, which still authorizes nothing.
|
|
683
|
+
*/
|
|
684
|
+
export declare function retiredGrantRefusal(raw: string): string | null;
|
|
685
|
+
/**
|
|
686
|
+
* Any grant, in one flat shape.
|
|
687
|
+
*
|
|
688
|
+
* Flat rather than a discriminated union because this module is vendored into
|
|
689
|
+
* the CLI, which compiles with `strict: false`: a caller reads `family` and
|
|
690
|
+
* then `key`, and the fields another family would have used are simply absent.
|
|
691
|
+
*/
|
|
692
|
+
export interface FunctionGrant {
|
|
693
|
+
family: GrantFamily;
|
|
694
|
+
/**
|
|
695
|
+
* The single component of a keyed family — the integration key or the
|
|
696
|
+
* secret name — or the VERB of a high-blast string (`delete` for
|
|
697
|
+
* `databases:delete`), so that no two exact capabilities in one family read
|
|
698
|
+
* as the same grant.
|
|
699
|
+
*/
|
|
700
|
+
key: string;
|
|
701
|
+
/** The authored string, so an error or a log line can quote it. */
|
|
702
|
+
raw: string;
|
|
703
|
+
}
|
|
704
|
+
export interface ParsedFunctionGrant {
|
|
705
|
+
grant?: FunctionGrant;
|
|
706
|
+
error?: string;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* A channel name's ceiling, and the reason it has one.
|
|
710
|
+
*
|
|
711
|
+
* The name rides in a `ConnectionMapping` row's document-id slot as
|
|
712
|
+
* `ch:<appId>:<channel>` and in every grant token's claims, so an unbounded
|
|
713
|
+
* name would be an unbounded key and an unbounded credential. 200 characters
|
|
714
|
+
* is {@link MAX_CAPABILITY_ENTRY_LENGTH}, kept for continuity with the rows
|
|
715
|
+
* #3184 already wrote.
|
|
716
|
+
*/
|
|
717
|
+
export declare const MAX_CHANNEL_NAME_LENGTH = 200;
|
|
718
|
+
export interface ParsedChannelName {
|
|
719
|
+
/** The segment before the first `:`. Absent when the name is refused. */
|
|
720
|
+
namespace?: string;
|
|
721
|
+
error?: string;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* A channel NAME, and its namespace.
|
|
725
|
+
*
|
|
726
|
+
* The grammar is the grant component charset applied per segment: one or more
|
|
727
|
+
* `[A-Za-z0-9_-]+` segments joined by `:`. The `channel:<namespace>` GRANT
|
|
728
|
+
* that used to cover a name is retired (#3279); the name grammar stays because
|
|
729
|
+
* the authorize and publish routes answer 400 about a name outside it before
|
|
730
|
+
* anything else, and the connection worker keys membership by it.
|
|
731
|
+
*
|
|
732
|
+
* Refusals name the segment that failed, because "channel name is invalid" on
|
|
733
|
+
* a name like `orders:a::b` tells an author nothing they cannot already see.
|
|
734
|
+
*/
|
|
735
|
+
export declare function parseChannelName(value: unknown): ParsedChannelName;
|
|
736
|
+
/**
|
|
737
|
+
* One capability entry as a grant, or the reason it is not one.
|
|
738
|
+
*
|
|
739
|
+
* The single entry point the enforcement path and both preflights use: a
|
|
740
|
+
* caller holds one authored string and asks what it grants, without having to
|
|
741
|
+
* know which of the shapes to try. Every diagnosis is specific — a retired
|
|
742
|
+
* string gets the retirement and what stays; a near miss in a kept family gets
|
|
743
|
+
* the family's own strings; a keyed family gets its charset rule.
|
|
744
|
+
*/
|
|
745
|
+
export declare function parseFunctionGrant(entry: unknown): ParsedFunctionGrant;
|
|
746
|
+
/**
|
|
747
|
+
* One shape rather than a discriminated union: this module is vendored into
|
|
748
|
+
* the CLI, which compiles with `strict: false`, where narrowing on a boolean
|
|
749
|
+
* literal discriminant does not hold. Both callers read `ok` and then the
|
|
750
|
+
* field they want, and the unused half is empty rather than absent.
|
|
751
|
+
*/
|
|
752
|
+
export interface ParsedCapabilities {
|
|
753
|
+
ok: boolean;
|
|
754
|
+
/** Deduped, in authored order — what the config row stores. Empty when refused. */
|
|
755
|
+
capabilities: string[];
|
|
756
|
+
/** Every grant, in authored order. */
|
|
757
|
+
allGrants: FunctionGrant[];
|
|
758
|
+
/**
|
|
759
|
+
* The retired strings that were SKIPPED, in authored order — populated only
|
|
760
|
+
* under `tolerateRetired` (see {@link parseCapabilities}); a strict parse
|
|
761
|
+
* refuses them instead and leaves this empty.
|
|
762
|
+
*/
|
|
763
|
+
retired: string[];
|
|
764
|
+
/** Empty when accepted. */
|
|
765
|
+
errors: string[];
|
|
766
|
+
}
|
|
767
|
+
export interface ParseCapabilitiesOptions {
|
|
768
|
+
/**
|
|
769
|
+
* Skip retired strings instead of refusing them — #3279 edge 25.
|
|
770
|
+
*
|
|
771
|
+
* The PUSH path is strict: a file that still declares a retired grant is
|
|
772
|
+
* refused with the retirement, because a line that is accepted and ignored
|
|
773
|
+
* is a line the author believes means something. The ENFORCEMENT path is
|
|
774
|
+
* tolerant: a config version pushed before #3279 carries retired strings in
|
|
775
|
+
* a row that can never be re-pushed to fix (its envelope is immutable), and
|
|
776
|
+
* refusing it there would break every function pushed before the change.
|
|
777
|
+
* Such a row authorizes exactly what it keeps, and the skipped strings are
|
|
778
|
+
* reported in `retired` so the caller can log them.
|
|
779
|
+
*/
|
|
780
|
+
tolerateRetired?: boolean;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* A whole `capabilities` list: shape, bounds, grammar, duplicates.
|
|
784
|
+
*
|
|
785
|
+
* The model's own caps are checked HERE rather than left to the StringSet
|
|
786
|
+
* field, so an over-long entry is a named push error instead of a late model
|
|
787
|
+
* throw after the R2 object has already been written (principle 6).
|
|
788
|
+
*/
|
|
789
|
+
export declare function parseCapabilities(value: unknown, options?: ParseCapabilitiesOptions): ParsedCapabilities;
|
|
790
|
+
/**
|
|
791
|
+
* The config-tree objects an `integration:` grant may name.
|
|
792
|
+
*
|
|
793
|
+
* Only the one family whose target is CONFIG-TREE state. `secret:` is absent
|
|
794
|
+
* on purpose (D3183-002): its values are provisioned per environment, out of
|
|
795
|
+
* band, and are not part of the reviewed tree at all, so the ordinary order of
|
|
796
|
+
* work is to push the function and then provision the value. Refusing an
|
|
797
|
+
* unprovisioned name at push would break that; a missing value at CALL time is
|
|
798
|
+
* a structured runtime error instead. The high-blast strings name no object.
|
|
799
|
+
*
|
|
800
|
+
* `null` means "this enforcement point could not find out". The CLI reads the
|
|
801
|
+
* tree and, when it can, a live listing; when neither is available it defers
|
|
802
|
+
* rather than guessing, because a preflight that refused a valid tree for
|
|
803
|
+
* being offline would be worse than one that lets the server have the last
|
|
804
|
+
* word. The server never passes null — it can always read its own rows.
|
|
805
|
+
*/
|
|
806
|
+
export interface KnownGrantTargets {
|
|
807
|
+
/** Non-archived integration keys, or null when unknown. */
|
|
808
|
+
integrations: ReadonlySet<string> | null;
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Grants naming an integration the app does not have.
|
|
812
|
+
*
|
|
813
|
+
* One message per offending grant, quoting the whole authored string AND the
|
|
814
|
+
* key on its own, so an operator reading the line knows both what to fix in
|
|
815
|
+
* the file and what to create in the app.
|
|
816
|
+
*
|
|
817
|
+
* The rule is here, beside the grammar, for the reason the whole module
|
|
818
|
+
* exists: `config push`'s preflight and the authoritative server check read
|
|
819
|
+
* different sources for the same facts — a `.toml` in the tree versus a row
|
|
820
|
+
* in DynamoDB — and it is the RULE that must not differ between them.
|
|
821
|
+
*/
|
|
822
|
+
export declare function validateKeyedGrantsAgainstTargets(grants: readonly FunctionGrant[], known: KnownGrantTargets): string[];
|
|
823
|
+
/**
|
|
824
|
+
* The query manifest's grammar, and the read rule it unlocks — #3187, project
|
|
825
|
+
* `server-functions` phase 5.
|
|
826
|
+
*
|
|
827
|
+
* A pushed config version may carry a MANIFEST: the queries and mutations the
|
|
828
|
+
* tree registered at module scope, collected by the CLI (`function-collect.ts`)
|
|
829
|
+
* by running the tree with `primitive-functions` aliased to a recording stub.
|
|
830
|
+
*
|
|
831
|
+
* ── What the manifest is for ─────────────────────────────────────────────
|
|
832
|
+
*
|
|
833
|
+
* Observability, and nothing else. `primitive functions get` and the admin
|
|
834
|
+
* get list what a version registered, so an operator can see it without
|
|
835
|
+
* reading the bundle (principle 8). The read rule it used to be decided from
|
|
836
|
+
* (#3187's `$caller` relaxation of `unscopedReads`) is retired by #3279:
|
|
837
|
+
* function code acts as the system, so there is no per-model grant for a
|
|
838
|
+
* binding to waive. The intent says so in as many words — "the models a
|
|
839
|
+
* function touches are collected at push as a reviewable manifest, not an
|
|
840
|
+
* authorization".
|
|
841
|
+
*
|
|
842
|
+
* It is HONEST-CODE evidence and the design doc says so: a hostile bundle can
|
|
843
|
+
* register whatever it likes, because the collector runs the tenant's own
|
|
844
|
+
* code. Nothing security-relevant at runtime reads it — parameter injection
|
|
845
|
+
* and cache verification happen in the platform-owned SDK inside the isolate,
|
|
846
|
+
* and the invocation gate remains the adversarial boundary.
|
|
847
|
+
*
|
|
848
|
+
* ── Why the grammar is here ──────────────────────────────────────────────
|
|
849
|
+
*
|
|
850
|
+
* Same reason as `function-grants.ts`: the CLI validates at push preflight so
|
|
851
|
+
* an author sees the error against their own tree, and the server validates
|
|
852
|
+
* authoritatively because the raw admin API exists. Two enforcement points,
|
|
853
|
+
* one rule, in the dependency-free tree the CLI vendors.
|
|
854
|
+
*/
|
|
855
|
+
/**
|
|
856
|
+
* The manifest encoding, versioned with the envelope that carries it.
|
|
857
|
+
*
|
|
858
|
+
* Version 2 (#3279 behavior 10) adds what a function TOUCHES beside what it
|
|
859
|
+
* registers: the deduplicated `models` its code names and the `families` of
|
|
860
|
+
* `ctx.api` and the ctx helpers it reaches, collected by a static scan of the
|
|
861
|
+
* built bundle, plus a `dynamicModels` marker for a model name the scan
|
|
862
|
+
* could not resolve — distinct from an empty list, which means "names none".
|
|
863
|
+
* A version-1 manifest still parses: it records registrations only.
|
|
864
|
+
*/
|
|
865
|
+
export declare const FUNCTION_MANIFEST_SCHEMA_VERSION = 2;
|
|
866
|
+
export declare const FUNCTION_MANIFEST_SCHEMA_VERSIONS: readonly [1, 2];
|
|
867
|
+
/** Bounds, so a manifest cannot be a way to store an unbounded blob. */
|
|
868
|
+
export declare const MAX_MANIFEST_QUERIES = 200;
|
|
869
|
+
export declare const MAX_MANIFEST_NAME_LENGTH = 120;
|
|
870
|
+
export declare const MAX_MANIFEST_MODELS = 200;
|
|
871
|
+
export declare const MAX_MANIFEST_FAMILIES = 40;
|
|
872
|
+
export interface ManifestParam {
|
|
873
|
+
type?: string;
|
|
874
|
+
caller?: boolean;
|
|
875
|
+
optional?: boolean;
|
|
876
|
+
default?: unknown;
|
|
877
|
+
}
|
|
878
|
+
export interface ManifestQuery {
|
|
879
|
+
name: string;
|
|
880
|
+
kind: "query" | "mutation";
|
|
881
|
+
models: string[];
|
|
882
|
+
params: Record<string, ManifestParam>;
|
|
883
|
+
cache: {
|
|
884
|
+
ttlMs: number;
|
|
885
|
+
} | null;
|
|
886
|
+
/** True when a `$caller` binding scopes this registration. */
|
|
887
|
+
callerScoped: boolean;
|
|
888
|
+
}
|
|
889
|
+
export interface FunctionManifest {
|
|
890
|
+
schemaVersion: number;
|
|
891
|
+
queries: ManifestQuery[];
|
|
892
|
+
/**
|
|
893
|
+
* Every model name the bundle names, deduplicated and sorted: registration
|
|
894
|
+
* declarations, literal `.model("…")` calls, and literal `modelName`/`model`
|
|
895
|
+
* arguments of the direct records and documents calls (#3279). Empty for a
|
|
896
|
+
* version-1 manifest, and for a function that names none.
|
|
897
|
+
*/
|
|
898
|
+
models: string[];
|
|
899
|
+
/** Every `ctx.api.<family>` and ctx-helper family the bundle reaches. */
|
|
900
|
+
families: string[];
|
|
901
|
+
/**
|
|
902
|
+
* The scan met a model name it could not resolve — a computed
|
|
903
|
+
* `modelName`, a `.model(variable)`. Says "and possibly more", which an
|
|
904
|
+
* empty `models` list does not.
|
|
905
|
+
*/
|
|
906
|
+
dynamicModels: boolean;
|
|
907
|
+
}
|
|
908
|
+
export interface ParsedManifest {
|
|
909
|
+
ok: boolean;
|
|
910
|
+
manifest: FunctionManifest | null;
|
|
911
|
+
errors: string[];
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Validate a manifest's grammar and normalize it.
|
|
915
|
+
*
|
|
916
|
+
* Deliberately strict about SHAPE and silent about meaning: whether the models
|
|
917
|
+
* exist, whether the queries are the ones the sandbox will really register,
|
|
918
|
+
* and whether the author meant any of it are questions this cannot answer.
|
|
919
|
+
*/
|
|
920
|
+
export declare function parseFunctionManifest(value: unknown): ParsedManifest;
|
|
581
921
|
export declare const WORKFLOW_SURFACE: ConfigObjectSurface;
|
|
582
922
|
export declare const PROMPT_SURFACE: ConfigObjectSurface;
|
|
583
923
|
export declare const INTEGRATION_SURFACE: ConfigObjectSurface;
|