@relyio/sdk 0.18.0 → 0.19.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/automations/index.cjs +18 -17
  3. package/dist/automations/index.d.cts +289 -8
  4. package/dist/automations/index.d.ts +289 -8
  5. package/dist/automations/index.js +3 -2
  6. package/dist/{chunk-ZHTJ7GXH.js → chunk-356SF5Y2.js} +84 -26
  7. package/dist/{chunk-ZAMAR3X2.cjs → chunk-5F3YYPLZ.cjs} +11249 -10771
  8. package/dist/{chunk-LSI26ZN2.cjs → chunk-DBYMG6MQ.cjs} +5 -5
  9. package/dist/{chunk-SHSK7UUY.cjs → chunk-NN45CSPZ.cjs} +177 -11
  10. package/dist/{chunk-IFKF72VJ.cjs → chunk-P23G5NXD.cjs} +122 -63
  11. package/dist/{chunk-W7JFHSFM.js → chunk-PZCDJFMA.js} +11249 -10772
  12. package/dist/{chunk-EDE2H37D.js → chunk-T7LGREB3.js} +174 -12
  13. package/dist/{chunk-R6E4HE7R.js → chunk-W2GRVXDG.js} +3 -3
  14. package/dist/client/index.cjs +4 -4
  15. package/dist/client/index.d.cts +4 -4
  16. package/dist/client/index.d.ts +4 -4
  17. package/dist/client/index.js +2 -2
  18. package/dist/{define-content-type-NEQDrvdq.d.cts → define-content-type-BZ6X8GvL.d.cts} +1324 -156
  19. package/dist/{define-content-type-fb-WCD5e.d.ts → define-content-type-C12jh8cY.d.ts} +1324 -156
  20. package/dist/{define-schema-Dlwh6l_J.d.ts → define-schema-BPlZl4a2.d.cts} +104 -3
  21. package/dist/{define-schema-DZhtvLiK.d.cts → define-schema-CK7TtYot.d.ts} +104 -3
  22. package/dist/extensions/index.cjs +26 -6
  23. package/dist/extensions/index.d.cts +5 -791
  24. package/dist/extensions/index.d.ts +5 -791
  25. package/dist/extensions/index.js +24 -4
  26. package/dist/functions/index.cjs +7 -4
  27. package/dist/functions/index.d.cts +4 -4
  28. package/dist/functions/index.d.ts +4 -4
  29. package/dist/functions/index.js +5 -2
  30. package/dist/{index-M3luH06A.d.ts → index-BxNnlc5D.d.ts} +91 -73
  31. package/dist/{index-C4LqrNd1.d.ts → index-C-MymZTe.d.ts} +1 -1
  32. package/dist/{index-DwHcL6x5.d.cts → index-D5jyIeQ5.d.cts} +91 -73
  33. package/dist/{index-Dnmt_UOo.d.cts → index-DN0l8RHw.d.cts} +1 -1
  34. package/dist/index.cjs +88 -84
  35. package/dist/index.d.cts +64 -14
  36. package/dist/index.d.ts +64 -14
  37. package/dist/index.js +4 -4
  38. package/dist/preview/index.cjs +3 -3
  39. package/dist/preview/index.js +1 -1
  40. package/dist/{register-B53i97A9.d.ts → register-BiMQKVp-.d.ts} +24 -8
  41. package/dist/{register-BYCs0FpF.d.cts → register-DeMsaurp.d.cts} +24 -8
  42. package/dist/rich-text/index.d.cts +2 -2
  43. package/dist/rich-text/index.d.ts +2 -2
  44. package/dist/schema/index.cjs +41 -40
  45. package/dist/schema/index.d.cts +7 -120
  46. package/dist/schema/index.d.ts +7 -120
  47. package/dist/schema/index.js +2 -1
  48. package/dist/types/index.d.cts +1 -1
  49. package/dist/types/index.d.ts +1 -1
  50. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @relyio/sdk
2
2
 
3
+ ## 0.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0c154b3: **Declare who may read and write each type.** A Record type takes an Owner field, `fields.owner()`, which RelyIO sets from the signed-in End user's token, and `endUsers` names its Policies — `read`, `create`, `update` (with the `fields` an End user may set) and `delete`, each `'owner'`, `'signedIn'`, `'anyone'` (for a read) or a condition built with `conditionRoot('record' | 'claims')`, `and`, `or` and `not`. `perUser.writesPerMinute` caps one End user's writes, and `onOwnerDeleted: 'delete' | 'keep'` says what becomes of their Records when their identity provider deletes them. A content type's `endUsers.read: { when, otherwise }` Gates it: an entry `when` holds of is served whole, any other as its `otherwise` fields with `_gated: true`. The rule types are exported from `@relyio/sdk/schema` as `PolicyRule`, `NamedPolicyRule`, `WriteRule`, `FieldsWriteRule`, `RecordWriteRule`, `RecordTypeEndUsers` and `OwnerDeletedAction`.
8
+
9
+ **Private fields.** `private: true` on a field keeps it from every publishable-key read and every End user's, whatever key they come with; your server and your Functions still read it.
10
+
11
+ **Clerk's users.** With Clerk in `relyio/extensions.ts`, `clerk.userRef()` declares a reference to a `clerkUser` — the Record RelyIO keeps for each of your Clerk users — and a signed-in End user reads their own `clerkUser`, by its list, by its id, or through an Owner field's include.
12
+
13
+ **Refusals you can catch.** A refused End user token is `EndUserTokenInvalidError`, with `reason` (`expired`, `wrong-audience`, `missing`, …). `PublishableKeyRefusedError` now says how to fix it: send the End user's token, declare `endUsers` on the Function, or call from your server. A unique value an End user's write collides with names no `recordId`: it may be a Record they cannot read.
14
+
15
+ - 6acd363: **Every request carries the signed-in End user's token.** Hand the client your identity provider's token function once — `createClient({ apiKey, getToken })`, Clerk's `getToken` or your own — and each request asks it then: a token is sent as `X-RelyIO-End-User` beside the key, and `null` (or a blank string) sends nothing, so the request is the key's alone. It is asked once per call, so every retry sends the token the first attempt sent; a function that throws rejects the call with nothing sent. It works with a publishable key in a browser and a secret key on a server. `client.with({ getToken })` makes a client that asks its own function in place of its parent's, and `updateConfig({ getToken: null })` stops sending one. A token the API cannot verify is refused `END_USER_TOKEN_INVALID` (401).
16
+
17
+ **Claims are typed from `relyio/extensions.ts`.** `ClaimsOf<typeof extensions>` (`@relyio/sdk/extensions`) is an object with one optional key per Claim the identity Extension's `claims` setting names — `oidc: { claims: 'plan, role' }` is `{ plan?: unknown; role?: unknown }` — so `conditionRoot<ClaimsOf<typeof extensions>>('claims').plan.eq('paid')` compiles and a misspelt Claim does not. A setting is text, so a Claim's value is `unknown`.
18
+
19
+ - 10d761f: **A browser may call a Function that says so.** `defineFunction({ endUsers: 'required', … })` lets a publishable key call it through `relyio.functions.<name>(input)` for a signed-in End user — the call carries their token (`getToken`), and without one it is refused `END_USER_TOKEN_INVALID` (401, reason `missing`); `endUsers: 'optional'` lets it call with or without one. A Function that declares neither is still refused to a publishable key (`PUBLISHABLE_KEY_REFUSED`). The run is bound by the Function's own reach either way — a checkout takes stock the shopper could never write — and the plan names a new or widened `endUsers`.
20
+
21
+ **`run.endUser` names who called.** Any call carrying a verified token — with any key, or to a Public route sent one — hands the run `run.endUser`: `{ subject, claims }`, the subject an Owner field stores, and the Claims your `relyio/extensions.ts` declares. Type them by registering it: `declare module '@relyio/sdk' { interface Register { extensions: typeof extensions } }`. A Record the run creates with no owner named is that End user's; name one to set it yourself.
22
+
3
23
  ## 0.18.0
4
24
 
5
25
  ### Minor Changes
@@ -1,70 +1,71 @@
1
1
  'use strict';
2
2
 
3
- var chunkLSI26ZN2_cjs = require('../chunk-LSI26ZN2.cjs');
4
- var chunkZAMAR3X2_cjs = require('../chunk-ZAMAR3X2.cjs');
3
+ var chunkDBYMG6MQ_cjs = require('../chunk-DBYMG6MQ.cjs');
4
+ var chunk5F3YYPLZ_cjs = require('../chunk-5F3YYPLZ.cjs');
5
+ require('../chunk-NN45CSPZ.cjs');
5
6
  require('../chunk-L6DXCKVQ.cjs');
6
7
 
7
8
 
8
9
 
9
10
  Object.defineProperty(exports, "and", {
10
11
  enumerable: true,
11
- get: function () { return chunkLSI26ZN2_cjs.and; }
12
+ get: function () { return chunkDBYMG6MQ_cjs.and; }
12
13
  });
13
14
  Object.defineProperty(exports, "anyEntry", {
14
15
  enumerable: true,
15
- get: function () { return chunkLSI26ZN2_cjs.anyEntry; }
16
+ get: function () { return chunkDBYMG6MQ_cjs.anyEntry; }
16
17
  });
17
18
  Object.defineProperty(exports, "automations", {
18
19
  enumerable: true,
19
- get: function () { return chunkLSI26ZN2_cjs.automations; }
20
+ get: function () { return chunkDBYMG6MQ_cjs.automations; }
20
21
  });
21
22
  Object.defineProperty(exports, "defineAutomation", {
22
23
  enumerable: true,
23
- get: function () { return chunkLSI26ZN2_cjs.defineAutomation; }
24
+ get: function () { return chunkDBYMG6MQ_cjs.defineAutomation; }
24
25
  });
25
26
  Object.defineProperty(exports, "entries", {
26
27
  enumerable: true,
27
- get: function () { return chunkLSI26ZN2_cjs.entries; }
28
+ get: function () { return chunkDBYMG6MQ_cjs.entries; }
28
29
  });
29
30
  Object.defineProperty(exports, "extensionTrigger", {
30
31
  enumerable: true,
31
- get: function () { return chunkLSI26ZN2_cjs.extensionTrigger; }
32
+ get: function () { return chunkDBYMG6MQ_cjs.extensionTrigger; }
32
33
  });
33
34
  Object.defineProperty(exports, "isAutomationFile", {
34
35
  enumerable: true,
35
- get: function () { return chunkLSI26ZN2_cjs.isAutomationFile; }
36
+ get: function () { return chunkDBYMG6MQ_cjs.isAutomationFile; }
36
37
  });
37
38
  Object.defineProperty(exports, "not", {
38
39
  enumerable: true,
39
- get: function () { return chunkLSI26ZN2_cjs.not; }
40
+ get: function () { return chunkDBYMG6MQ_cjs.not; }
40
41
  });
41
42
  Object.defineProperty(exports, "on", {
42
43
  enumerable: true,
43
- get: function () { return chunkLSI26ZN2_cjs.on; }
44
+ get: function () { return chunkDBYMG6MQ_cjs.on; }
44
45
  });
45
46
  Object.defineProperty(exports, "or", {
46
47
  enumerable: true,
47
- get: function () { return chunkLSI26ZN2_cjs.or; }
48
+ get: function () { return chunkDBYMG6MQ_cjs.or; }
48
49
  });
49
50
  Object.defineProperty(exports, "records", {
50
51
  enumerable: true,
51
- get: function () { return chunkLSI26ZN2_cjs.records; }
52
+ get: function () { return chunkDBYMG6MQ_cjs.records; }
52
53
  });
53
54
  Object.defineProperty(exports, "resolveAutomation", {
54
55
  enumerable: true,
55
- get: function () { return chunkLSI26ZN2_cjs.resolveAutomation; }
56
+ get: function () { return chunkDBYMG6MQ_cjs.resolveAutomation; }
56
57
  });
57
58
  Object.defineProperty(exports, "schedule", {
58
59
  enumerable: true,
59
- get: function () { return chunkLSI26ZN2_cjs.schedule; }
60
+ get: function () { return chunkDBYMG6MQ_cjs.schedule; }
60
61
  });
61
62
  Object.defineProperty(exports, "tpl", {
62
63
  enumerable: true,
63
- get: function () { return chunkLSI26ZN2_cjs.tpl; }
64
+ get: function () { return chunkDBYMG6MQ_cjs.tpl; }
64
65
  });
65
66
  Object.defineProperty(exports, "fields", {
66
67
  enumerable: true,
67
- get: function () { return chunkZAMAR3X2_cjs.fields; }
68
+ get: function () { return chunk5F3YYPLZ_cjs.fields; }
68
69
  });
69
70
  //# sourceMappingURL=index.cjs.map
70
71
  //# sourceMappingURL=index.cjs.map
@@ -1,8 +1,7 @@
1
- import { ConditionScalar, ConditionTest, ConditionTree, ConditionTests } from '../schema/index.cjs';
1
+ import { cH as ConditionScalar, cI as ConditionTest, cK as ConditionTree, cJ as ConditionTests, r as KeyedMembers, an as FieldValues, ao as DeclaredFields, s as KeyedMembersOf, cM as ExtensionSurfaces, cN as ExtensionSettingField, cO as ExtensionSurface, cP as ActionField, cQ as ExtensionValueField, y as ReferenceConfig, o as KeyedFieldOptions, n as KeyedField, cx as FileUpload } from '../define-content-type-BZ6X8GvL.cjs';
2
+ import { A as AnySchemaDefinition, R as RegisteredSchema, B as BaseRecord, a as RecordBatchTarget, b as RecordBatchResult, c as Register, d as RecordConditionValue } from '../register-DeMsaurp.cjs';
3
+ import { i as SchemaRecordTypeNames, I as InferRecordType, b as SchemaContentTypeNames, j as SchemaEntry, f as SchemaLocaleCodes, r as RecordWriteFieldsOf, q as RecordUpdateFieldsOf } from '../define-schema-BPlZl4a2.cjs';
2
4
  export { fields } from '../schema/index.cjs';
3
- import { A as AnySchemaDefinition, R as RegisteredSchema, B as BaseRecord, a as RecordBatchTarget, b as RecordBatchResult, c as RecordConditionValue } from '../register-BYCs0FpF.cjs';
4
- import { S as SchemaRecordTypeNames, I as InferRecordType, a as SchemaContentTypeNames, b as SchemaEntry, c as SchemaLocaleCodes, R as RecordWriteFieldsOf, d as RecordUpdateFieldsOf } from '../define-schema-DZhtvLiK.cjs';
5
- import { K as KeyedMembers, F as FieldValues, D as DeclaredFields, a as KeyedMembersOf, b as FileUpload } from '../define-content-type-NEQDrvdq.cjs';
6
5
  import '../rich-text.d-BWc-5gX1.cjs';
7
6
 
8
7
  /**
@@ -600,7 +599,7 @@ interface StepWithOutput<O> extends StepHandle {
600
599
  readonly output: Ref<O>;
601
600
  }
602
601
  /** A Field set's values, as a Function's and an Agent step's output Fields declare them. */
603
- type ValuesOf$1<F extends KeyedMembers> = FieldValues<DeclaredFields<{
602
+ type ValuesOf$2<F extends KeyedMembers> = FieldValues<DeclaredFields<{
604
603
  readonly fields: readonly KeyedMembersOf<F>[];
605
604
  }>>;
606
605
  /** What `step.agent` takes. */
@@ -770,9 +769,9 @@ interface StepBuilder {
770
769
  * Ask an agent to read, answer the declared Fields and propose one change to the types `propose`
771
770
  * names. Nothing it proposes is written until an Ask approves it (`step.ask(…, { approve })`).
772
771
  */
773
- agent<const O extends KeyedMembers>(name: string, config: ProposingAgentStepConfig<O>): StepWithOutput<ProposingOutput<ValuesOf$1<O>>>;
772
+ agent<const O extends KeyedMembers>(name: string, config: ProposingAgentStepConfig<O>): StepWithOutput<ProposingOutput<ValuesOf$2<O>>>;
774
773
  /** Ask an agent to read and answer the declared Fields. It reads; it never writes or sends. */
775
- agent<const O extends KeyedMembers>(name: string, config: AgentStepConfig<O>): StepWithOutput<ValuesOf$1<O>>;
774
+ agent<const O extends KeyedMembers>(name: string, config: AgentStepConfig<O>): StepWithOutput<ValuesOf$2<O>>;
776
775
  /** Send through an Extension's Action, from the events worker; Recorded in a Preview without its Connection. */
777
776
  action<I, O>(name: string, action: AutomationAction<I, O>, input: StepInput<I>): StepWithOutput<O>;
778
777
  /**
@@ -863,6 +862,249 @@ declare function isAutomationFile(value: unknown): value is AutomationFile;
863
862
  */
864
863
  declare function resolveAutomation(file: AutomationFile, nameOf: (fn: FunctionDefinition) => string | undefined): AutomationDefinition;
865
864
 
865
+ /**
866
+ * `@relyio/sdk/extensions` — the Extensions a Project uses (spec 3, REL-3846; ADR 0019).
867
+ *
868
+ * One file, `relyio/extensions.ts`, names each Extension the Project uses and its settings — set once
869
+ * for the Project, never per Environment — and hands out a typed handle for each. An Automation
870
+ * imports the handle: its Triggers start an Automation (`on: vercel.deploymentSucceeded()`), and its
871
+ * Actions are what `step.action` sends through, their input and output typed by the Extension.
872
+ *
873
+ * @example
874
+ * // relyio/extensions.ts
875
+ * import { defineExtensions } from '@relyio/sdk/extensions'
876
+ *
877
+ * const extensions = defineExtensions({
878
+ * slack: { defaultChannel: '#orders' },
879
+ * vercel: {},
880
+ * })
881
+ * export const { slack, vercel } = extensions
882
+ * export default extensions
883
+ *
884
+ * **Never a secret here.** A Connection — an API key, a signing secret, a webhook URL — is made in
885
+ * the Dashboard, once per Environment, and sealed. A setting is text anyone reading the repository
886
+ * may see. Declaring an Extension connects nothing: `relyio plan` says which still need connecting
887
+ * in Production, and which Automations will deploy paused there until they are. Preview never pauses:
888
+ * an Action with no Preview Connection is Recorded with its sample result.
889
+ *
890
+ * **Typed.** Each Extension's settings, Actions and Triggers are RelyIO's own declaration of it
891
+ * (`@relyio/api-contract`'s `EXTENSION_SURFACES`, which the Extension catalog delivers): an Extension
892
+ * RelyIO does not have, a setting it does not declare, or a value its setting does not take — a
893
+ * Slack channel without its `#` — is a type error, and the plan refuses it again for a Manifest read
894
+ * as data.
895
+ */
896
+
897
+ /** One Extension a Project uses: its settings, by key. */
898
+ interface ExtensionUse {
899
+ readonly settings: Readonly<Record<string, string>>;
900
+ }
901
+ /** What `relyio/extensions.ts` declares, as data: every Extension the Project uses, by slug. */
902
+ type ExtensionsDeclaration = Readonly<Record<string, ExtensionUse>>;
903
+ /** Every Extension a Project may declare, and what its code may name of each. */
904
+ type Surfaces = ExtensionSurfaces;
905
+ /** The value one setting takes: one of its options, text starting with its prefix, or text. */
906
+ type SettingValue<F extends ExtensionSettingField> = F extends {
907
+ readonly type: 'select';
908
+ readonly options: ReadonlyArray<infer Option>;
909
+ } ? Option : F extends {
910
+ readonly type: 'text';
911
+ readonly prefix: infer Prefix extends string;
912
+ } ? `${Prefix}${string}` : string;
913
+ type Flatten<T> = {
914
+ readonly [K in keyof T]: T[K];
915
+ };
916
+ /** The settings an Extension takes: its required ones required, the rest optional, nothing else. */
917
+ type SettingsFrom<F extends ExtensionSettingField> = Flatten<{
918
+ readonly [Field in F as Field extends {
919
+ readonly required: true;
920
+ } ? Field['key'] : never]: SettingValue<Field>;
921
+ } & {
922
+ readonly [Field in F as Field extends {
923
+ readonly required: true;
924
+ } ? never : Field['key']]?: SettingValue<Field>;
925
+ }>;
926
+ /**
927
+ * The settings `defineExtensions` takes for Extension `S`. An Extension with none takes `{}` and
928
+ * nothing in it.
929
+ */
930
+ type ExtensionSettings<S extends keyof Surfaces> = [
931
+ Surfaces[S]['settings'][number]
932
+ ] extends [never] ? Readonly<Record<string, never>> : SettingsFrom<Surfaces[S]['settings'][number]>;
933
+ /** What `defineExtensions` takes: each Extension the Project uses, by slug, with its settings. */
934
+ type ExtensionsConfig = {
935
+ readonly [S in keyof Surfaces]?: ExtensionSettings<S>;
936
+ };
937
+ /** A value field's JSON type, as TypeScript reads it. */
938
+ type JsonOf<T extends ExtensionValueField['type']> = T extends 'string' ? string : T extends 'number' ? number : T extends 'boolean' ? boolean : T extends 'array' ? readonly unknown[] : Readonly<Record<string, unknown>>;
939
+ /** A dot-separated path's first segment. */
940
+ type Head<P extends string> = P extends `${infer First}.${string}` ? First : P;
941
+ /** The fields whose path starts with segment `K`. */
942
+ type Under<F extends ExtensionValueField, K extends string> = F extends ExtensionValueField ? Head<F['path']> extends K ? F : never : never;
943
+ /** The fields under `K`, their paths with `K.` taken off; never for the field at `K` itself. */
944
+ type Rebased<F extends ExtensionValueField, K extends string> = F extends ExtensionValueField ? F['path'] extends `${K}.${infer Rest}` ? Omit<F, 'path'> & {
945
+ readonly path: Rest;
946
+ } : never : never;
947
+ /** A field's value: its JSON type, and an object of strings for one declaring string values. */
948
+ type FieldValueOf<F extends ExtensionValueField> = F extends {
949
+ readonly values: 'string';
950
+ } ? Readonly<Record<string, string>> : JsonOf<F['type']>;
951
+ /** The value at `K`: the field there, or an object of the fields under it. */
952
+ type ValueAt<F extends ExtensionValueField, K extends string> = [
953
+ Extract<F, {
954
+ readonly path: K;
955
+ }>
956
+ ] extends [never] ? ValuesOf$1<Rebased<F, K>> : FieldValueOf<Extract<F, {
957
+ readonly path: K;
958
+ }>>;
959
+ /**
960
+ * Value fields as an object: `payload.data.object.id` a `string` at `payload.data.object.id`. A
961
+ * segment is required when a field under it is.
962
+ */
963
+ type ValuesOf$1<F extends ExtensionValueField> = Flatten<{
964
+ readonly [K in Head<F['path']> as true extends Under<F, K>['required'] ? K : never]: ValueAt<F, K>;
965
+ } & {
966
+ readonly [K in Head<F['path']> as true extends Under<F, K>['required'] ? never : K]?: ValueAt<F, K>;
967
+ }>;
968
+ /** A Trigger's payload, as an object; one that declares nothing, `{}`. */
969
+ type ValuesOfList<L extends readonly ExtensionValueField[]> = [L[number]] extends [never] ? Record<string, never> : ValuesOf$1<L[number]>;
970
+ /** An action field's value, as TypeScript reads it (`@relyio/api-contract`'s `ACTION_FIELD_TYPES`). */
971
+ type ActionValueOf<T extends ActionField['type']> = T extends 'text' | 'url' ? string : T extends 'number' ? number : T extends 'boolean' ? boolean : T extends 'headers' ? Readonly<Record<string, string>> : AutomationJson;
972
+ /** An Action's input or output fields as an object: required ones required, the rest optional. */
973
+ type ActionValuesOf<L extends readonly ActionField[]> = Flatten<{
974
+ readonly [F in L[number] as F extends {
975
+ readonly required: true;
976
+ } ? F['key'] : never]: ActionValueOf<F['type']>;
977
+ } & {
978
+ readonly [F in L[number] as F extends {
979
+ readonly required: true;
980
+ } ? never : F['key']]?: ActionValueOf<F['type']>;
981
+ }>;
982
+ /** A Trigger's handle: call it for the Automation's `on`, with a `where` over its event if needed. */
983
+ type ExtensionTriggerHandle<P> = (options?: {
984
+ readonly where?: (event: Ref<ExtensionTriggerEvent<P>>) => ConditionTree;
985
+ }) => AutomationTriggerHandle<ExtensionTriggerEvent<P>>;
986
+ /**
987
+ * The handle an Extension's declaration gives: each of its Actions and Triggers, by the name it gives
988
+ * them, typed by their fields.
989
+ */
990
+ type HandleOf<X extends ExtensionSurface, S extends string = string> = {
991
+ readonly [A in keyof X['actions']]: X['actions'][A] extends {
992
+ readonly action: infer N extends string;
993
+ readonly step: {
994
+ readonly input: infer I extends readonly ActionField[];
995
+ readonly output: infer O extends readonly ActionField[];
996
+ };
997
+ } ? AutomationAction<ActionValuesOf<I>, ActionValuesOf<O>, S, N> : never;
998
+ } & {
999
+ readonly [T in keyof X['triggers']]: X['triggers'][T] extends {
1000
+ readonly payload: infer P extends readonly ExtensionValueField[];
1001
+ } ? ExtensionTriggerHandle<ValuesOfList<P>> : never;
1002
+ };
1003
+ /**
1004
+ * A contributed field kind's options (spec 4, REL-3894): its base reference's, without `to`, which
1005
+ * the kind names, and never `localized` — a user is no translation.
1006
+ */
1007
+ type ContributedFieldOptions<TTo extends string, TMulti extends boolean, TRequired extends boolean> = Omit<ReferenceConfig<TTo, TMulti>, 'to'> & {
1008
+ readonly required?: TRequired;
1009
+ readonly to?: never;
1010
+ } & KeyedFieldOptions<never>;
1011
+ /**
1012
+ * A contributed field kind's builder — `clerk.userRef()`: a reference to the Extension's Managed
1013
+ * Record type, typed exactly as `fields.reference` types a reference to it, which the Studio picks through
1014
+ * the kind's picker. The schema, reads, writes and Policies treat it as that reference.
1015
+ */
1016
+ type ContributedFieldKindBuilder<TTo extends string> = <TMulti extends boolean = false, TRequired extends boolean = false>(options?: ContributedFieldOptions<TTo, TMulti, TRequired>) => KeyedField<'reference', ReferenceConfig<TTo, TMulti> & {
1017
+ required?: TRequired;
1018
+ }>;
1019
+ /** An Extension's contributed field kinds, by the name its declaration gives them. */
1020
+ type FieldKindsOf<X extends ExtensionSurface> = {
1021
+ readonly [K in keyof X['fieldKinds']]: X['fieldKinds'][K] extends {
1022
+ readonly base: {
1023
+ readonly to: infer To extends string;
1024
+ };
1025
+ } ? ContributedFieldKindBuilder<To> : never;
1026
+ };
1027
+ /** An Extension's Managed Record types, by the name its declaration gives them (REL-3863). */
1028
+ type RecordTypesOf<X extends ExtensionSurface> = {
1029
+ readonly [K in keyof X['recordTypes']]: X['recordTypes'][K];
1030
+ };
1031
+ /** Extension `S`'s handle. */
1032
+ type ExtensionHandle<S extends keyof Surfaces> = HandleOf<Surfaces[S], S & string> & FieldKindsOf<Surfaces[S]> & RecordTypesOf<Surfaces[S]>;
1033
+ /** Where the declaration rides on what `defineExtensions` returns. */
1034
+ declare const DECLARED = "declared";
1035
+ /**
1036
+ * Where an {@link ExtensionsFile}'s type keeps the settings it was declared with, for
1037
+ * {@link ClaimsOf} to read. Type-level only: no value carries it.
1038
+ */
1039
+ declare const DECLARED_SETTINGS: unique symbol;
1040
+ /**
1041
+ * What `relyio/extensions.ts` default-exports: the declaration the CLI reads into the Manifest, and
1042
+ * a handle for each Extension it declares.
1043
+ */
1044
+ type ExtensionsFile<C> = ExtensionsFileData & {
1045
+ readonly [S in keyof C & keyof Surfaces]: ExtensionHandle<S>;
1046
+ } & {
1047
+ readonly [DECLARED_SETTINGS]?: C;
1048
+ };
1049
+ /** The setting an identity Extension declares its Claims in (`@relyio/api-contract`'s `IDENTITY_CLAIMS_SETTING`). */
1050
+ type ClaimsSetting = 'claims';
1051
+ /** `S` without the whitespace `String.prototype.trim` takes off either end. */
1052
+ type Trimmed<S extends string> = S extends `${' ' | '\n' | '\t' | '\r'}${infer Rest}` ? Trimmed<Rest> : S extends `${infer Rest}${' ' | '\n' | '\t' | '\r'}` ? Trimmed<Rest> : S;
1053
+ /**
1054
+ * The Claim names a `claims` setting declares, read as `claimNamesOf` reads it at deploy: split on
1055
+ * commas, each trimmed, empty ones dropped. Text TypeScript does not know (`string`) may name any.
1056
+ */
1057
+ type ClaimNames<S extends string> = string extends S ? string : S extends `${infer First},${infer Rest}` ? ClaimNames<First> | ClaimNames<Rest> : Trimmed<S> extends '' ? never : Trimmed<S>;
1058
+ /** Every Claim name the Extensions in `C` declare: an identity Extension's `claims` setting. */
1059
+ type DeclaredClaimNames<C> = {
1060
+ readonly [S in keyof C]: C[S] extends {
1061
+ readonly [K in ClaimsSetting]: infer T extends string;
1062
+ } ? ClaimNames<T> : never;
1063
+ }[keyof C];
1064
+ /**
1065
+ * The Claims a Project relies on, typed from its `relyio/extensions.ts`: `ClaimsOf<typeof
1066
+ * extensions>` is an object with one optional key per Claim its identity Extension's `claims`
1067
+ * setting names — `claims: 'plan, role'` is `{ plan?: unknown; role?: unknown }`. A Claim named and
1068
+ * missing from a token is absent, and a setting is text, so each value is `unknown`: what a Claim may
1069
+ * hold is for the Policy that tests it to say.
1070
+ *
1071
+ * Type a Policy's `claims` root with it, so a misspelt Claim is a compile error:
1072
+ *
1073
+ * @example
1074
+ * import type { ClaimsOf } from '@relyio/sdk/extensions'
1075
+ * import { conditionRoot } from '@relyio/sdk/schema'
1076
+ * import extensions from './extensions'
1077
+ *
1078
+ * const claims = conditionRoot<ClaimsOf<typeof extensions>>('claims')
1079
+ * claims.plan.eq('paid') // ✓
1080
+ * claims.plna.eq('paid') // ✗ `plna` is no Claim the Project declares
1081
+ */
1082
+ type ClaimsOf<F> = F extends {
1083
+ readonly [DECLARED_SETTINGS]?: infer C;
1084
+ } ? {
1085
+ readonly [N in DeclaredClaimNames<C>]?: unknown;
1086
+ } : never;
1087
+ /** `C`, refusing a key no Extension declares — at the top and in each Extension's settings. */
1088
+ type Exactly<C> = {
1089
+ readonly [S in keyof C]: S extends keyof Surfaces ? C[S] & {
1090
+ readonly [K in Exclude<keyof C[S], keyof ExtensionSettings<S>>]: never;
1091
+ } : never;
1092
+ };
1093
+ /**
1094
+ * Declare the Extensions the Project uses, with their settings, and take a typed handle for each.
1095
+ * The file is `relyio/extensions.ts`; `relyio deploy` reads its default export into the Manifest.
1096
+ */
1097
+ declare function defineExtensions<const C extends ExtensionsConfig>(config: C & Exactly<C>): ExtensionsFile<C>;
1098
+ /** What the CLI reads of `relyio/extensions.ts`' default export, whatever it declares. */
1099
+ interface ExtensionsFileData {
1100
+ readonly _tag: 'extensions';
1101
+ readonly [DECLARED]: ExtensionsDeclaration;
1102
+ }
1103
+ /** Whether `value` is what `defineExtensions` returns: how the CLI reads `relyio/extensions.ts`. */
1104
+ declare function isExtensionsFile(value: unknown): value is ExtensionsFileData;
1105
+ /** The declaration as the Manifest carries it. */
1106
+ declare function extensionsDeclarationOf(file: ExtensionsFileData): ExtensionsDeclaration;
1107
+
866
1108
  /**
867
1109
  * `@relyio/sdk/functions` — a Function, declared (spec 2, REL-3819; ADR 0021).
868
1110
  *
@@ -979,6 +1221,8 @@ interface FunctionDeclaration {
979
1221
  readonly secrets: Readonly<Record<string, FunctionSecretDeclaration>>;
980
1222
  /** The Actions it may send (REL-3856); absent when it declares none. */
981
1223
  readonly actions?: readonly FunctionActionReach[];
1224
+ /** Who besides a secret key may call its SDK Way in (spec 4, REL-3892); absent when undeclared. */
1225
+ readonly endUsers?: FunctionEndUsers;
982
1226
  readonly route?: FunctionRoute;
983
1227
  readonly tool?: FunctionTool;
984
1228
  readonly schedule?: FunctionSchedule;
@@ -1124,6 +1368,31 @@ type FunctionRecords<R extends string, W extends string> = {
1124
1368
  * the person's own Preview branch.
1125
1369
  */
1126
1370
  type FunctionWayIn = 'sdk' | 'route' | 'tool' | 'schedule' | 'automation' | 'editor';
1371
+ /**
1372
+ * Whether a publishable key may call a Function from a browser (spec 4, REL-3892): `'required'` for
1373
+ * a signed-in End user only — the call carries their token — or `'optional'` with or without one.
1374
+ */
1375
+ type FunctionEndUsers = 'required' | 'optional';
1376
+ /**
1377
+ * The Claims a run's End user carries: those the registered `relyio/extensions.ts` declares
1378
+ * (`ClaimsOf`), once `Register` names it — `declare module '@relyio/sdk' { interface Register {
1379
+ * extensions: typeof extensions } }` — else any name, each `unknown`.
1380
+ */
1381
+ type FunctionEndUserClaims = Register extends {
1382
+ extensions: infer F;
1383
+ } ? ClaimsOf<F> : {
1384
+ readonly [claim: string]: unknown;
1385
+ };
1386
+ /**
1387
+ * The End user a run's call carried a verified token for (spec 4, REL-3892): their subject — the
1388
+ * `sub` an Owner field stores — and the Claims the Project declares, as the token carries them. A
1389
+ * Record the run creates naming no owner is theirs; what the run may touch is still its reach, never
1390
+ * their Policies.
1391
+ */
1392
+ interface FunctionEndUser {
1393
+ readonly subject: string;
1394
+ readonly claims: FunctionEndUserClaims;
1395
+ }
1127
1396
  /** What a run knows of itself: its id survives every retry. */
1128
1397
  interface FunctionRunInfo {
1129
1398
  readonly id: string;
@@ -1146,6 +1415,11 @@ interface FunctionRunInfo {
1146
1415
  * Absent from a run an SDK call, a route or a tool started.
1147
1416
  */
1148
1417
  readonly event?: Readonly<Record<string, unknown>>;
1418
+ /**
1419
+ * The End user whose token the call carried, verified (spec 4, REL-3892) — with any key on the SDK
1420
+ * Way in or a keyed route, and on a Public route that was sent one. Absent otherwise.
1421
+ */
1422
+ readonly endUser?: FunctionEndUser;
1149
1423
  }
1150
1424
  /** Published content, read through the read core: present when the reach declares `content: 'published'`. */
1151
1425
  interface FunctionContent {
@@ -1272,6 +1546,13 @@ interface FunctionConfig<I extends KeyedMembers, O extends KeyedMembers, R exten
1272
1546
  * type error, and refused at run time.
1273
1547
  */
1274
1548
  actions?: readonly A[];
1549
+ /**
1550
+ * Who besides a secret key may call it through `relyio.functions.<name>(input)` (spec 4,
1551
+ * REL-3892): `'required'` lets a publishable key call it for a signed-in End user, whose token it
1552
+ * carries; `'optional'` lets a publishable key call it with or without one. Left out, a secret key
1553
+ * alone. Either way the run is bound by its reach, and `run.endUser` names who called.
1554
+ */
1555
+ endUsers?: FunctionEndUsers;
1275
1556
  route?: FunctionRoute;
1276
1557
  tool?: FunctionTool;
1277
1558
  schedule?: FunctionSchedule;
@@ -1306,4 +1587,4 @@ declare function defineFunction<const I extends KeyedMembers = Record<never, nev
1306
1587
  /** Whether `value` is what `defineFunction` returns: how the CLI reads a Function file's default export. */
1307
1588
  declare function isFunctionDefinition(value: unknown): value is FunctionDefinition;
1308
1589
 
1309
- export { type FunctionActionRefused as A, type Accepts, type AgentStepConfig, type AnyEntryEvent, type AnyEntryTriggers, type ApproveCounts, type ApproveOutput, type ApproveStepConfig, type AskOutput, type AskStepConfig, type AutomationAction, type AutomationBecomesTest, type AutomationConfig, type AutomationDefinition, type AutomationDuration, type AutomationEntryAction, type AutomationFile, type AutomationInput, type AutomationItemHandle, type AutomationItemRef, type AutomationJson, type AutomationLookupState, type AutomationProposal, type AutomationProposeTarget, type AutomationRecordAction, type AutomationRef, type AutomationStep, type AutomationStepDraft, type AutomationTemplate, type AutomationTrigger, type AutomationTriggerHandle, type AutomationValue, type AutomationWhere, isActionRefused as B, type FunctionCapabilities as C, type FunctionResponse as D, respond as E, type EntryEvent, type EntryTriggers, type ExtensionTriggerEvent, type FunctionRuntime as F, type FunctionConfig as G, type FunctionDefinition as H, type FunctionInputOf as I, type FunctionOutputOf as J, defineFunction as K, isFunctionDefinition as L, type LookedUp, type LookedUpEntry, type LookedUpEntryItem, type LookedUpRecord, type LookupOptions, type ProposingAgentStepConfig, type ProposingOutput, type RecordEvent, type RecordTriggers, type Ref, type RunFailedEvent, type RunFailedWhere, type StepBuilder, type StepHandle, type StepInput, type StepWithOutput, type TriggerWhere, type UidRef, type FunctionContainerSize as a, and, anyEntry, automations, type FunctionDuration as b, type FunctionRouteMethod as c, type FunctionNetworkHost as d, defineAutomation, type FunctionActionReach as e, entries, extensionTrigger, type FunctionActionHandle as f, type FunctionSecretDeclaration as g, type FunctionRoute as h, type FunctionTool as i, isAutomationFile, type FunctionSchedule as j, type FunctionFieldDeclaration as k, type FunctionDeclaration as l, type FunctionRecordTypeName as m, type FunctionFile as n, not, type FunctionCounterMove as o, on, or, type FunctionRecordReader as p, type FunctionRecordWriter as q, type FunctionRecordBatch as r, records, resolveAutomation, type FunctionBatchResult as s, schedule, type FunctionBatchRefused as t, tpl, isBatchRefused as u, type FunctionRecords as v, type FunctionWayIn as w, type FunctionRunInfo as x, type FunctionContent as y, type FunctionActions as z };
1590
+ export { type FunctionOutputOf as $, type FunctionCounterMove as A, type Accepts, type AgentStepConfig, type AnyEntryEvent, type AnyEntryTriggers, type ApproveCounts, type ApproveOutput, type ApproveStepConfig, type AskOutput, type AskStepConfig, type AutomationAction, type AutomationBecomesTest, type AutomationConfig, type AutomationDefinition, type AutomationDuration, type AutomationEntryAction, type AutomationFile, type AutomationInput, type AutomationItemHandle, type AutomationItemRef, type AutomationJson, type AutomationLookupState, type AutomationProposal, type AutomationProposeTarget, type AutomationRecordAction, type AutomationRef, type AutomationStep, type AutomationStepDraft, type AutomationTemplate, type AutomationTrigger, type AutomationTriggerHandle, type AutomationValue, type AutomationWhere, type FunctionRecordReader as B, type ContributedFieldOptions as C, type FunctionRecordWriter as D, type ExtensionUse as E, type EntryEvent, type EntryTriggers, type ExtensionTriggerEvent, type FunctionRuntime as F, type FunctionRecordBatch as G, type HandleOf as H, type FunctionBatchResult as I, type FunctionBatchRefused as J, isBatchRefused as K, type FunctionRecords as L, type LookedUp, type LookedUpEntry, type LookedUpEntryItem, type LookedUpRecord, type LookupOptions, type FunctionWayIn as M, type FunctionEndUsers as N, type FunctionEndUserClaims as O, type FunctionEndUser as P, type ProposingAgentStepConfig, type ProposingOutput, type FunctionRunInfo as Q, type FunctionContent as R, type RecordEvent, type RecordTriggers, type Ref, type RunFailedEvent, type RunFailedWhere, type FunctionActions as S, type StepBuilder, type StepHandle, type StepInput, type StepWithOutput, type FunctionActionRefused as T, type TriggerWhere, isActionRefused as U, type UidRef, type FunctionCapabilities as V, type FunctionResponse as W, respond as X, type FunctionConfig as Y, type FunctionDefinition as Z, type FunctionInputOf as _, type ExtensionsDeclaration as a, defineFunction as a0, isFunctionDefinition as a1, and, anyEntry, automations, type ExtensionSettings as b, type ExtensionsConfig as c, type ExtensionTriggerHandle as d, defineAutomation, type ContributedFieldKindBuilder as e, entries, extensionTrigger, type ExtensionHandle as f, type ExtensionsFile as g, type ClaimsOf as h, defineExtensions as i, isAutomationFile, type ExtensionsFileData as j, isExtensionsFile as k, extensionsDeclarationOf as l, type FunctionContainerSize as m, type FunctionDuration as n, not, type FunctionRouteMethod as o, on, or, type FunctionNetworkHost as p, type FunctionActionReach as q, type FunctionActionHandle as r, records, resolveAutomation, type FunctionSecretDeclaration as s, schedule, type FunctionRoute as t, tpl, type FunctionTool as u, type FunctionSchedule as v, type FunctionFieldDeclaration as w, type FunctionDeclaration as x, type FunctionRecordTypeName as y, type FunctionFile as z };