@party-stack/foundry-ontology 0.19.0 → 0.20.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 (202) hide show
  1. package/README.md +53 -32
  2. package/lib/adapter/backend.d.ts +35 -0
  3. package/lib/adapter/backend.d.ts.map +1 -0
  4. package/lib/adapter/backend.js +210 -0
  5. package/lib/adapter/backend.js.map +1 -0
  6. package/lib/adapter/encrypted.d.ts +12 -0
  7. package/lib/adapter/encrypted.d.ts.map +1 -0
  8. package/lib/adapter/encrypted.js +79 -0
  9. package/lib/adapter/encrypted.js.map +1 -0
  10. package/lib/adapter/foundryActionError.d.ts +7 -0
  11. package/lib/adapter/foundryActionError.d.ts.map +1 -0
  12. package/lib/adapter/foundryActionError.js +61 -0
  13. package/lib/adapter/foundryActionError.js.map +1 -0
  14. package/lib/adapter/foundryActionValidation.d.ts +4 -3
  15. package/lib/adapter/foundryActionValidation.d.ts.map +1 -1
  16. package/lib/adapter/foundryActionValidation.js +71 -25
  17. package/lib/adapter/foundryActionValidation.js.map +1 -1
  18. package/lib/adapter/foundryCodec.d.ts +2 -5
  19. package/lib/adapter/foundryCodec.d.ts.map +1 -1
  20. package/lib/adapter/foundryCodec.js +19 -7
  21. package/lib/adapter/foundryCodec.js.map +1 -1
  22. package/lib/adapter/foundryObjectSearch.d.ts +13 -0
  23. package/lib/adapter/foundryObjectSearch.d.ts.map +1 -0
  24. package/lib/adapter/foundryObjectSearch.js +57 -0
  25. package/lib/adapter/foundryObjectSearch.js.map +1 -0
  26. package/lib/adapter/index.d.ts +3 -4
  27. package/lib/adapter/index.js +3 -4
  28. package/lib/adapter/likeFilter.d.ts +10 -0
  29. package/lib/adapter/likeFilter.d.ts.map +1 -0
  30. package/lib/adapter/likeFilter.js +87 -0
  31. package/lib/adapter/likeFilter.js.map +1 -0
  32. package/lib/adapter/makeFoundryOntologyBackend.d.ts +76 -0
  33. package/lib/adapter/makeFoundryOntologyBackend.d.ts.map +1 -0
  34. package/lib/adapter/makeFoundryOntologyBackend.js +505 -0
  35. package/lib/adapter/makeFoundryOntologyBackend.js.map +1 -0
  36. package/lib/adapter/subsetFilter.d.ts +14 -0
  37. package/lib/adapter/subsetFilter.d.ts.map +1 -0
  38. package/lib/adapter/subsetFilter.js +105 -0
  39. package/lib/adapter/subsetFilter.js.map +1 -0
  40. package/lib/adapter/uploads.d.ts +25 -0
  41. package/lib/adapter/uploads.d.ts.map +1 -0
  42. package/lib/adapter/uploads.js +78 -0
  43. package/lib/adapter/uploads.js.map +1 -0
  44. package/lib/backend.d.ts +80 -0
  45. package/lib/backend.d.ts.map +1 -0
  46. package/lib/backend.js +34 -0
  47. package/lib/backend.js.map +1 -0
  48. package/lib/config/index.d.ts +8 -12
  49. package/lib/config/index.d.ts.map +1 -1
  50. package/lib/config/index.js +49 -52
  51. package/lib/config/index.js.map +1 -1
  52. package/lib/connectionOptions.d.ts +9 -0
  53. package/lib/connectionOptions.d.ts.map +1 -0
  54. package/lib/connectionOptions.js +1 -0
  55. package/lib/context.d.ts +21 -0
  56. package/lib/context.d.ts.map +1 -0
  57. package/lib/context.js +16 -0
  58. package/lib/context.js.map +1 -0
  59. package/lib/index.d.ts +7 -7
  60. package/lib/index.js +6 -7
  61. package/lib/meta/backend.d.ts +10 -0
  62. package/lib/meta/backend.d.ts.map +1 -0
  63. package/lib/meta/backend.js +161 -0
  64. package/lib/meta/backend.js.map +1 -0
  65. package/lib/meta/convertMetaActionType.d.ts +3 -2
  66. package/lib/meta/convertMetaActionType.d.ts.map +1 -1
  67. package/lib/meta/convertMetaActionType.js +3 -3
  68. package/lib/meta/convertMetaActionType.js.map +1 -1
  69. package/lib/meta/convertMetaLinkType.d.ts +2 -2
  70. package/lib/meta/convertMetaLinkType.d.ts.map +1 -1
  71. package/lib/meta/convertMetaLinkType.js +13 -13
  72. package/lib/meta/convertMetaLinkType.js.map +1 -1
  73. package/lib/meta/convertMetaObjectType.d.ts +2 -2
  74. package/lib/meta/convertMetaObjectType.d.ts.map +1 -1
  75. package/lib/meta/convertMetaObjectType.js +5 -1
  76. package/lib/meta/convertMetaObjectType.js.map +1 -1
  77. package/lib/meta/convertMetaQueryFunctionType.d.ts +1 -1
  78. package/lib/meta/convertMetaQueryFunctionType.js.map +1 -1
  79. package/lib/meta/convertMetaTypeDef.d.ts +1 -1
  80. package/lib/meta/convertMetaTypeDef.d.ts.map +1 -1
  81. package/lib/meta/convertMetaTypeDef.js +7 -1
  82. package/lib/meta/convertMetaTypeDef.js.map +1 -1
  83. package/lib/meta/convertMetaValueType.d.ts +2 -2
  84. package/lib/meta/convertMetaValueType.d.ts.map +1 -1
  85. package/lib/meta/convertMetaValueType.js.map +1 -1
  86. package/lib/meta/convertOmsActionParameterMetadata.d.ts +1 -1
  87. package/lib/meta/convertOmsActionParameterMetadata.js +1 -1
  88. package/lib/meta/convertOmsActionParameterMetadata.js.map +1 -1
  89. package/lib/meta/index.d.ts +2 -4
  90. package/lib/meta/index.js +2 -4
  91. package/lib/meta/listObjectTypes.d.ts +6 -0
  92. package/lib/meta/listObjectTypes.d.ts.map +1 -0
  93. package/lib/meta/listObjectTypes.js +13 -0
  94. package/lib/meta/listObjectTypes.js.map +1 -0
  95. package/lib/meta/loadActions.d.ts +7 -0
  96. package/lib/meta/loadActions.d.ts.map +1 -0
  97. package/lib/meta/loadActions.js +20 -0
  98. package/lib/meta/loadActions.js.map +1 -0
  99. package/lib/meta/loadEntities.d.ts +9 -0
  100. package/lib/meta/loadEntities.d.ts.map +1 -0
  101. package/lib/meta/loadEntities.js +73 -0
  102. package/lib/meta/loadEntities.js.map +1 -0
  103. package/lib/meta/loadQueryFunctions.d.ts +11 -0
  104. package/lib/meta/loadQueryFunctions.d.ts.map +1 -0
  105. package/lib/meta/loadQueryFunctions.js +18 -0
  106. package/lib/meta/loadQueryFunctions.js.map +1 -0
  107. package/lib/meta/planMetaLookup.d.ts +12 -0
  108. package/lib/meta/planMetaLookup.d.ts.map +1 -0
  109. package/lib/meta/planMetaLookup.js +44 -0
  110. package/lib/meta/planMetaLookup.js.map +1 -0
  111. package/lib/platform.d.ts +78 -0
  112. package/lib/platform.d.ts.map +1 -0
  113. package/lib/platform.js +116 -0
  114. package/lib/platform.js.map +1 -0
  115. package/lib/platformCollections.d.ts +68 -0
  116. package/lib/platformCollections.d.ts.map +1 -0
  117. package/lib/platformCollections.js +7 -0
  118. package/lib/platformCollections.js.map +1 -0
  119. package/lib/serviceConnector.d.ts +8 -0
  120. package/lib/serviceConnector.d.ts.map +1 -0
  121. package/lib/serviceConnector.js +105 -0
  122. package/lib/serviceConnector.js.map +1 -0
  123. package/lib/stagedWrites.d.ts +3 -2
  124. package/lib/stagedWrites.d.ts.map +1 -1
  125. package/lib/stagedWrites.js +30 -3
  126. package/lib/stagedWrites.js.map +1 -1
  127. package/lib/users/admin.d.ts +105 -0
  128. package/lib/users/admin.d.ts.map +1 -0
  129. package/lib/users/admin.js +35 -0
  130. package/lib/users/admin.js.map +1 -0
  131. package/lib/users/createFoundryUsersIntegration.d.ts +2 -2
  132. package/lib/users/createFoundryUsersIntegration.d.ts.map +1 -1
  133. package/lib/users/createFoundryUsersIntegration.js +4 -6
  134. package/lib/users/createFoundryUsersIntegration.js.map +1 -1
  135. package/lib/users/foundryUser.d.ts +2 -2
  136. package/lib/users/foundryUser.js +1 -1
  137. package/lib/users/foundryUser.js.map +1 -1
  138. package/lib/users/index.d.ts +2 -3
  139. package/lib/users/index.js +2 -3
  140. package/lib/users/loadUserSubset.d.ts +8 -0
  141. package/lib/users/loadUserSubset.d.ts.map +1 -0
  142. package/lib/users/loadUserSubset.js +166 -0
  143. package/lib/users/loadUserSubset.js.map +1 -0
  144. package/lib/utils/AsyncIterable.d.ts +1 -1
  145. package/lib/utils/AsyncIterable.d.ts.map +1 -1
  146. package/lib/utils/AsyncIterable.js +11 -0
  147. package/lib/utils/AsyncIterable.js.map +1 -1
  148. package/package.json +16 -15
  149. package/lib/adapter/convertLoadSubsetOptions.d.ts +0 -8
  150. package/lib/adapter/convertLoadSubsetOptions.d.ts.map +0 -1
  151. package/lib/adapter/convertLoadSubsetOptions.js +0 -178
  152. package/lib/adapter/convertLoadSubsetOptions.js.map +0 -1
  153. package/lib/adapter/createFoundryOntologyBackendAdapter.d.ts +0 -29
  154. package/lib/adapter/createFoundryOntologyBackendAdapter.d.ts.map +0 -1
  155. package/lib/adapter/createFoundryOntologyBackendAdapter.js +0 -311
  156. package/lib/adapter/createFoundryOntologyBackendAdapter.js.map +0 -1
  157. package/lib/adapter/objectCollectionOptions.d.ts +0 -33
  158. package/lib/adapter/objectCollectionOptions.d.ts.map +0 -1
  159. package/lib/adapter/objectCollectionOptions.js +0 -482
  160. package/lib/adapter/objectCollectionOptions.js.map +0 -1
  161. package/lib/config/applyAttachmentConstraintOverrides.d.ts +0 -10
  162. package/lib/config/applyAttachmentConstraintOverrides.d.ts.map +0 -1
  163. package/lib/config/applyAttachmentConstraintOverrides.js +0 -50
  164. package/lib/config/applyAttachmentConstraintOverrides.js.map +0 -1
  165. package/lib/connection.d.ts +0 -38
  166. package/lib/connection.d.ts.map +0 -1
  167. package/lib/connection.js +0 -195
  168. package/lib/connection.js.map +0 -1
  169. package/lib/installation/createFoundryBackendInstallation.d.ts +0 -29
  170. package/lib/installation/createFoundryBackendInstallation.d.ts.map +0 -1
  171. package/lib/installation/createFoundryBackendInstallation.js +0 -60
  172. package/lib/installation/createFoundryBackendInstallation.js.map +0 -1
  173. package/lib/installation/index.d.ts +0 -2
  174. package/lib/installation/index.js +0 -1
  175. package/lib/meta/actionTypeCollectionOptions.d.ts +0 -14
  176. package/lib/meta/actionTypeCollectionOptions.d.ts.map +0 -1
  177. package/lib/meta/actionTypeCollectionOptions.js +0 -58
  178. package/lib/meta/actionTypeCollectionOptions.js.map +0 -1
  179. package/lib/meta/convertActionTypeLoadSubsetOptions.d.ts +0 -7
  180. package/lib/meta/convertActionTypeLoadSubsetOptions.d.ts.map +0 -1
  181. package/lib/meta/convertActionTypeLoadSubsetOptions.js +0 -84
  182. package/lib/meta/convertActionTypeLoadSubsetOptions.js.map +0 -1
  183. package/lib/meta/createFoundryMetaOntologyBackendAdapter.d.ts +0 -11
  184. package/lib/meta/createFoundryMetaOntologyBackendAdapter.d.ts.map +0 -1
  185. package/lib/meta/createFoundryMetaOntologyBackendAdapter.js +0 -43
  186. package/lib/meta/createFoundryMetaOntologyBackendAdapter.js.map +0 -1
  187. package/lib/meta/entityCollectionOptions.d.ts +0 -25
  188. package/lib/meta/entityCollectionOptions.d.ts.map +0 -1
  189. package/lib/meta/entityCollectionOptions.js +0 -69
  190. package/lib/meta/entityCollectionOptions.js.map +0 -1
  191. package/lib/meta/queryFunctionTypeCollectionOptions.d.ts +0 -12
  192. package/lib/meta/queryFunctionTypeCollectionOptions.d.ts.map +0 -1
  193. package/lib/meta/queryFunctionTypeCollectionOptions.js +0 -59
  194. package/lib/meta/queryFunctionTypeCollectionOptions.js.map +0 -1
  195. package/lib/users/createFoundryAdminOntologyRoute.d.ts +0 -55
  196. package/lib/users/createFoundryAdminOntologyRoute.d.ts.map +0 -1
  197. package/lib/users/createFoundryAdminOntologyRoute.js +0 -33
  198. package/lib/users/createFoundryAdminOntologyRoute.js.map +0 -1
  199. package/lib/users/userCollectionOptions.d.ts +0 -25
  200. package/lib/users/userCollectionOptions.d.ts.map +0 -1
  201. package/lib/users/userCollectionOptions.js +0 -94
  202. package/lib/users/userCollectionOptions.js.map +0 -1
@@ -0,0 +1,78 @@
1
+ import { ConnectionEgress } from "@party-stack/connect";
2
+ import { Effect } from "effect";
3
+ import { Infer } from "@party-stack/ontology-spec";
4
+ //#region src/platform.d.ts
5
+ /** Account-visible inventory, separate from one selected ontology's type metadata. */
6
+ export declare const foundryPlatformOntology: {
7
+ types: never[];
8
+ context: {
9
+ type: {
10
+ kind: "struct";
11
+ value: {
12
+ fields: {
13
+ name: "userId";
14
+ displayName: "User ID";
15
+ type: {
16
+ kind: "string";
17
+ value: {};
18
+ };
19
+ }[];
20
+ };
21
+ };
22
+ partition: string[][];
23
+ };
24
+ objectTypes: {
25
+ name: "Ontology";
26
+ displayName: "Ontology";
27
+ pluralDisplayName: "Ontologies";
28
+ primaryKey: "id";
29
+ title: "displayName";
30
+ properties: ({
31
+ name: "id";
32
+ displayName: "ID";
33
+ type: {
34
+ kind: "string";
35
+ value: {};
36
+ };
37
+ } | {
38
+ name: "rid";
39
+ displayName: "RID";
40
+ type: {
41
+ kind: "string";
42
+ value: {};
43
+ };
44
+ } | {
45
+ name: "apiName";
46
+ displayName: "API name";
47
+ type: {
48
+ kind: "string";
49
+ value: {};
50
+ };
51
+ } | {
52
+ name: "displayName";
53
+ displayName: "Name";
54
+ type: {
55
+ kind: "string";
56
+ value: {};
57
+ };
58
+ } | {
59
+ name: "description";
60
+ displayName: "Description";
61
+ type: {
62
+ kind: "string";
63
+ value: {};
64
+ };
65
+ })[];
66
+ }[];
67
+ linkTypes: never[];
68
+ actionTypes: never[];
69
+ queryFunctionTypes: never[];
70
+ };
71
+ export type FoundryPlatformOntology = Infer<typeof foundryPlatformOntology>;
72
+ /** Uses the selected account's authenticated egress; it stores no credentials or rows. */
73
+ export declare const makeFoundryPlatformBackend: (options: {
74
+ readonly baseUrl: string;
75
+ readonly egress: ConnectionEgress;
76
+ }) => Effect.Effect<import("@party-stack/ontology-backend").OntologyBackendService, never, import("effect/Scope").Scope>;
77
+ //#endregion
78
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","names":[],"sources":["../src/platform.ts"],"mappings":";;;;;qBAaa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAwBD,0BAA0B,aAAa;;qBAuBtC,6BAA0B;WACjB;WACD,QAAA;MA8CnB,OAAA,+CAAA,sDAAA"}
@@ -0,0 +1,116 @@
1
+ import { foundryContext } from "./context.js";
2
+ import { toWebEgress } from "@party-stack/connect";
3
+ import { createClient } from "@party-stack/foundry-client";
4
+ import { Effect, Redacted, Schema } from "effect";
5
+ import { OntologiesV2 } from "@osdk/foundry.ontologies";
6
+ import { BackendError, classifyBackendFailure, makeOntologyBackend } from "@party-stack/ontology-backend";
7
+ import { defineOntology, o } from "@party-stack/ontology-spec";
8
+ import { compileObjectSubset, objectSubset } from "@party-stack/ontology-backend/subset";
9
+ //#region src/platform.ts
10
+ /** Account-visible inventory, separate from one selected ontology's type metadata. */
11
+ const foundryPlatformOntology = defineOntology({
12
+ types: [],
13
+ context: foundryContext,
14
+ objectTypes: [{
15
+ name: "Ontology",
16
+ displayName: "Ontology",
17
+ pluralDisplayName: "Ontologies",
18
+ primaryKey: "id",
19
+ title: "displayName",
20
+ properties: [
21
+ {
22
+ name: "id",
23
+ displayName: "ID",
24
+ type: o.string({})
25
+ },
26
+ {
27
+ name: "rid",
28
+ displayName: "RID",
29
+ type: o.string({})
30
+ },
31
+ {
32
+ name: "apiName",
33
+ displayName: "API name",
34
+ type: o.string({})
35
+ },
36
+ {
37
+ name: "displayName",
38
+ displayName: "Name",
39
+ type: o.string({})
40
+ },
41
+ {
42
+ name: "description",
43
+ displayName: "Description",
44
+ type: o.string({})
45
+ }
46
+ ]
47
+ }],
48
+ linkTypes: [],
49
+ actionTypes: [],
50
+ queryFunctionTypes: []
51
+ });
52
+ const inventory = Schema.Struct({ data: Schema.Array(Schema.Struct({
53
+ rid: Schema.NonEmptyString,
54
+ apiName: Schema.NonEmptyString,
55
+ displayName: Schema.String,
56
+ description: Schema.String
57
+ })) });
58
+ const unsupported = (operation) => Effect.fail(new BackendError({
59
+ operation,
60
+ kind: "NotImplemented",
61
+ retryable: false,
62
+ message: "Foundry platform inventory is read-only."
63
+ }));
64
+ /** Uses the selected account's authenticated egress; it stores no credentials or rows. */
65
+ const makeFoundryPlatformBackend = Effect.fnUntraced(function* (options) {
66
+ const web = yield* toWebEgress(options.egress);
67
+ const client = createClient({
68
+ baseUrl: options.baseUrl,
69
+ fetch: web.fetch
70
+ });
71
+ return makeOntologyBackend({
72
+ ir: foundryPlatformOntology,
73
+ name: "foundry-platform",
74
+ sourceId: `foundry-platform:${client.baseUrl}`,
75
+ supportsIdempotency: false,
76
+ refresh: () => ({ pollIntervalMs: false }),
77
+ applyAction: () => unsupported("foundry.platform.applyAction"),
78
+ queryFunction: () => unsupported("foundry.platform.queryFunction"),
79
+ loadSubset: Effect.fn("FoundryPlatform.loadSubset")(function* (request) {
80
+ yield* compileObjectSubset(foundryPlatformOntology, request);
81
+ const response = yield* Effect.tryPromise({
82
+ try: (signal) => OntologiesV2.list({
83
+ ...client,
84
+ fetch: (input, init) => client.fetch(input, {
85
+ ...init,
86
+ signal: init?.signal ? AbortSignal.any([signal, init.signal]) : signal
87
+ })
88
+ }),
89
+ catch: (cause) => classifyBackendFailure("foundry.platform.listOntologies", cause)
90
+ });
91
+ const { data: values } = yield* Schema.decodeUnknownEffect(inventory)(response).pipe(Effect.mapError((cause) => new BackendError({
92
+ operation: "foundry.platform.decode",
93
+ kind: "InvalidResponse",
94
+ retryable: false,
95
+ message: "Foundry returned invalid ontology inventory.",
96
+ cause: Redacted.make(cause)
97
+ })));
98
+ return {
99
+ rows: values.map((value) => ({
100
+ key: value.rid,
101
+ value: {
102
+ id: value.rid,
103
+ ...value
104
+ }
105
+ })),
106
+ complete: true,
107
+ fulfilledSubset: objectSubset("Ontology"),
108
+ fetchedRows: values.length
109
+ };
110
+ })
111
+ });
112
+ });
113
+ //#endregion
114
+ export { foundryPlatformOntology, makeFoundryPlatformBackend };
115
+
116
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","names":[],"sources":["../src/platform.ts"],"sourcesContent":["import { OntologiesV2 } from \"@osdk/foundry.ontologies\";\nimport { toWebEgress } from \"@party-stack/connect\";\nimport { createClient } from \"@party-stack/foundry-client\";\nimport { BackendError, classifyBackendFailure, makeOntologyBackend } from \"@party-stack/ontology-backend\";\nimport { compileObjectSubset, objectSubset } from \"@party-stack/ontology-backend/subset\";\nimport { defineOntology, o } from \"@party-stack/ontology-spec\";\nimport { Effect, Redacted, Schema } from \"effect\";\nimport { foundryContext } from \"./context.js\";\nimport type { ConnectionEgress } from \"@party-stack/connect\";\nimport type { Infer } from \"@party-stack/ontology-spec\";\nimport type { ObjectSubset } from \"@party-stack/ontology-spec/query\";\n\n/** Account-visible inventory, separate from one selected ontology's type metadata. */\nexport const foundryPlatformOntology = defineOntology({\n types: [],\n context: foundryContext,\n objectTypes: [\n {\n name: \"Ontology\",\n displayName: \"Ontology\",\n pluralDisplayName: \"Ontologies\",\n primaryKey: \"id\",\n title: \"displayName\",\n properties: [\n { name: \"id\", displayName: \"ID\", type: o.string({}) },\n { name: \"rid\", displayName: \"RID\", type: o.string({}) },\n { name: \"apiName\", displayName: \"API name\", type: o.string({}) },\n { name: \"displayName\", displayName: \"Name\", type: o.string({}) },\n { name: \"description\", displayName: \"Description\", type: o.string({}) },\n ],\n },\n ],\n linkTypes: [],\n actionTypes: [],\n queryFunctionTypes: [],\n});\n\nexport type FoundryPlatformOntology = Infer<typeof foundryPlatformOntology>;\n\nconst inventory = Schema.Struct({\n data: Schema.Array(\n Schema.Struct({\n rid: Schema.NonEmptyString,\n apiName: Schema.NonEmptyString,\n displayName: Schema.String,\n description: Schema.String,\n })\n ),\n});\nconst unsupported = (operation: string) =>\n Effect.fail(\n new BackendError({\n operation,\n kind: \"NotImplemented\",\n retryable: false,\n message: \"Foundry platform inventory is read-only.\",\n })\n );\n\n/** Uses the selected account's authenticated egress; it stores no credentials or rows. */\nexport const makeFoundryPlatformBackend = Effect.fnUntraced(function* (options: {\n readonly baseUrl: string;\n readonly egress: ConnectionEgress;\n}) {\n const web = yield* toWebEgress(options.egress);\n const client = createClient({ baseUrl: options.baseUrl, fetch: web.fetch });\n return makeOntologyBackend({\n ir: foundryPlatformOntology,\n name: \"foundry-platform\",\n sourceId: `foundry-platform:${client.baseUrl}`,\n supportsIdempotency: false,\n refresh: () => ({ pollIntervalMs: false }),\n applyAction: () => unsupported(\"foundry.platform.applyAction\"),\n queryFunction: () => unsupported(\"foundry.platform.queryFunction\"),\n loadSubset: Effect.fn(\"FoundryPlatform.loadSubset\")(function* (request: ObjectSubset) {\n yield* compileObjectSubset(foundryPlatformOntology, request);\n const response = yield* Effect.tryPromise({\n try: (signal) =>\n OntologiesV2.list({\n ...client,\n fetch: (input, init) =>\n client.fetch(input, {\n ...init,\n signal: init?.signal ? AbortSignal.any([signal, init.signal]) : signal,\n }),\n }),\n catch: (cause) => classifyBackendFailure(\"foundry.platform.listOntologies\", cause),\n });\n const { data: values } = yield* Schema.decodeUnknownEffect(inventory)(response).pipe(\n Effect.mapError(\n (cause) =>\n new BackendError({\n operation: \"foundry.platform.decode\",\n kind: \"InvalidResponse\",\n retryable: false,\n message: \"Foundry returned invalid ontology inventory.\",\n cause: Redacted.make(cause),\n })\n )\n );\n return {\n rows: values.map((value) => ({ key: value.rid, value: { id: value.rid, ...value } })),\n complete: true,\n fulfilledSubset: objectSubset(\"Ontology\"),\n fetchedRows: values.length,\n };\n }),\n });\n});\n"],"mappings":";;;;;;;;;;AAaA,MAAa,0BAA0B,eAAe;CAClD,OAAO,CAAC;CACR,SAAS;CACT,aAAa,CACT;EACI,MAAM;EACN,aAAa;EACb,mBAAmB;EACnB,YAAY;EACZ,OAAO;EACP,YAAY;GACR;IAAE,MAAM;IAAM,aAAa;IAAM,MAAM,EAAE,OAAO,CAAC,CAAC;GAAE;GACpD;IAAE,MAAM;IAAO,aAAa;IAAO,MAAM,EAAE,OAAO,CAAC,CAAC;GAAE;GACtD;IAAE,MAAM;IAAW,aAAa;IAAY,MAAM,EAAE,OAAO,CAAC,CAAC;GAAE;GAC/D;IAAE,MAAM;IAAe,aAAa;IAAQ,MAAM,EAAE,OAAO,CAAC,CAAC;GAAE;GAC/D;IAAE,MAAM;IAAe,aAAa;IAAe,MAAM,EAAE,OAAO,CAAC,CAAC;GAAE;EAC1E;CACJ,CACJ;CACA,WAAW,CAAC;CACZ,aAAa,CAAC;CACd,oBAAoB,CAAC;AACzB,CAAC;AAID,MAAM,YAAY,OAAO,OAAO,EAC5B,MAAM,OAAO,MACT,OAAO,OAAO;CACV,KAAK,OAAO;CACZ,SAAS,OAAO;CAChB,aAAa,OAAO;CACpB,aAAa,OAAO;AACxB,CAAC,CACL,EACJ,CAAC;AACD,MAAM,eAAe,cACjB,OAAO,KACH,IAAI,aAAa;CACb;CACA,MAAM;CACN,WAAW;CACX,SAAS;AACb,CAAC,CACL;;AAGJ,MAAa,6BAA6B,OAAO,WAAW,WAAW,SAGpE;CACC,MAAM,MAAM,OAAO,YAAY,QAAQ,MAAM;CAC7C,MAAM,SAAS,aAAa;EAAE,SAAS,QAAQ;EAAS,OAAO,IAAI;CAAM,CAAC;CAC1E,OAAO,oBAAoB;EACvB,IAAI;EACJ,MAAM;EACN,UAAU,oBAAoB,OAAO;EACrC,qBAAqB;EACrB,gBAAgB,EAAE,gBAAgB,MAAM;EACxC,mBAAmB,YAAY,8BAA8B;EAC7D,qBAAqB,YAAY,gCAAgC;EACjE,YAAY,OAAO,GAAG,4BAA4B,CAAC,CAAC,WAAW,SAAuB;GAClF,OAAO,oBAAoB,yBAAyB,OAAO;GAC3D,MAAM,WAAW,OAAO,OAAO,WAAW;IACtC,MAAM,WACF,aAAa,KAAK;KACd,GAAG;KACH,QAAQ,OAAO,SACX,OAAO,MAAM,OAAO;MAChB,GAAG;MACH,QAAQ,MAAM,SAAS,YAAY,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI;KACpE,CAAC;IACT,CAAC;IACL,QAAQ,UAAU,uBAAuB,mCAAmC,KAAK;GACrF,CAAC;GACD,MAAM,EAAE,MAAM,WAAW,OAAO,OAAO,oBAAoB,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,KAC5E,OAAO,UACF,UACG,IAAI,aAAa;IACb,WAAW;IACX,MAAM;IACN,WAAW;IACX,SAAS;IACT,OAAO,SAAS,KAAK,KAAK;GAC9B,CAAC,CACT,CACJ;GACA,OAAO;IACH,MAAM,OAAO,KAAK,WAAW;KAAE,KAAK,MAAM;KAAK,OAAO;MAAE,IAAI,MAAM;MAAK,GAAG;KAAM;IAAE,EAAE;IACpF,UAAU;IACV,iBAAiB,aAAa,UAAU;IACxC,aAAa,OAAO;GACxB;EACJ,CAAC;CACL,CAAC;AACL,CAAC"}
@@ -0,0 +1,68 @@
1
+ //#region src/platformCollections.d.ts
2
+ export declare const foundryPlatformObjects: import("@party-stack/ontology").OntologyCollectionDescriptors<import("@party-stack/ontology-spec").InferOntology<{
3
+ types: never[];
4
+ context: {
5
+ type: {
6
+ kind: "struct";
7
+ value: {
8
+ fields: {
9
+ name: "userId";
10
+ displayName: "User ID";
11
+ type: {
12
+ kind: "string";
13
+ value: {};
14
+ };
15
+ }[];
16
+ };
17
+ };
18
+ partition: string[][];
19
+ };
20
+ objectTypes: {
21
+ name: "Ontology";
22
+ displayName: "Ontology";
23
+ pluralDisplayName: "Ontologies";
24
+ primaryKey: "id";
25
+ title: "displayName";
26
+ properties: ({
27
+ name: "id";
28
+ displayName: "ID";
29
+ type: {
30
+ kind: "string";
31
+ value: {};
32
+ };
33
+ } | {
34
+ name: "rid";
35
+ displayName: "RID";
36
+ type: {
37
+ kind: "string";
38
+ value: {};
39
+ };
40
+ } | {
41
+ name: "apiName";
42
+ displayName: "API name";
43
+ type: {
44
+ kind: "string";
45
+ value: {};
46
+ };
47
+ } | {
48
+ name: "displayName";
49
+ displayName: "Name";
50
+ type: {
51
+ kind: "string";
52
+ value: {};
53
+ };
54
+ } | {
55
+ name: "description";
56
+ displayName: "Description";
57
+ type: {
58
+ kind: "string";
59
+ value: {};
60
+ };
61
+ })[];
62
+ }[];
63
+ linkTypes: never[];
64
+ actionTypes: never[];
65
+ queryFunctionTypes: never[];
66
+ }>, Record<never, never>>;
67
+ //#endregion
68
+ //# sourceMappingURL=platformCollections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platformCollections.d.ts","names":[],"sources":["../src/platformCollections.ts"],"mappings":";qBAGwB,wDAAsB,mEAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE5C"}
@@ -0,0 +1,7 @@
1
+ import { ontologyCollections } from "@party-stack/ontology";
2
+ //#region src/platformCollections.ts
3
+ const { objects: foundryPlatformObjects } = ontologyCollections({ Ontology: "id" });
4
+ //#endregion
5
+ export { foundryPlatformObjects };
6
+
7
+ //# sourceMappingURL=platformCollections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platformCollections.js","names":[],"sources":["../src/platformCollections.ts"],"sourcesContent":["import { ontologyCollections } from \"@party-stack/ontology\";\nimport type { FoundryPlatformOntology } from \"./platform.js\";\n\nexport const { objects: foundryPlatformObjects } = ontologyCollections<FoundryPlatformOntology>({\n Ontology: \"id\",\n});\n"],"mappings":";;AAGA,MAAa,EAAE,SAAS,2BAA2B,oBAA6C,EAC5F,UAAU,KACd,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { ServiceConnector } from "@party-stack/connect";
2
+ //#region src/serviceConnector.d.ts
3
+ /** Reusable integration; the saved ServiceInstance supplies the Foundry stack URL. */
4
+ export declare function makeFoundryServiceConnector(options?: {
5
+ readonly fetch?: typeof globalThis.fetch;
6
+ }): ServiceConnector;
7
+ //#endregion
8
+ //# sourceMappingURL=serviceConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceConnector.d.ts","names":[],"sources":["../src/serviceConnector.ts"],"mappings":";;;wBAagB,4BACZ;WACa,eAAe,WAAW;IAExC"}
@@ -0,0 +1,105 @@
1
+ import { ConnectError, makeOAuthService, toWebEgress, withHttpAuthenticationErrors } from "@party-stack/connect";
2
+ import { createFoundryFetch, createFoundryWebSocket, getTokenDetails } from "@party-stack/foundry-client";
3
+ import { Effect, Fiber, Schema } from "effect";
4
+ import { BackendError, classifyBackendFailure } from "@party-stack/ontology-backend";
5
+ import { Temporal } from "temporal-polyfill";
6
+ //#region src/serviceConnector.ts
7
+ /** Reusable integration; the saved ServiceInstance supplies the Foundry stack URL. */
8
+ function makeFoundryServiceConnector(options = {}) {
9
+ const defaultScopes = [
10
+ "api:use-ontologies-read",
11
+ "api:use-ontologies-write",
12
+ "api:use-mediasets-read",
13
+ "api:use-mediasets-write",
14
+ "offline_access"
15
+ ];
16
+ const identity = (token) => Effect.try({
17
+ try: () => getTokenDetails(token),
18
+ catch: () => new ConnectError({
19
+ kind: "NeedsAuthentication",
20
+ retryable: false,
21
+ message: "Foundry credentials are invalid."
22
+ })
23
+ });
24
+ return {
25
+ service: "foundry",
26
+ displayName: "Foundry",
27
+ defaultOAuthScopes: defaultScopes,
28
+ oauth: Effect.fnUntraced(function* ({ application, serviceInstance, values }) {
29
+ const base = serviceInstance.instanceUrl.replace(/\/$/, "");
30
+ const secret = application.clientSecret ? yield* values.decrypt(Schema.String, application.clientSecret).pipe(Effect.mapError(() => new ConnectError({
31
+ kind: "Storage",
32
+ retryable: false,
33
+ message: "OAuth client secret is unavailable."
34
+ }))) : void 0;
35
+ return makeOAuthService({
36
+ issuer: `${base}/multipass/`,
37
+ authorizationEndpoint: `${base}/multipass/api/oauth2/authorize`,
38
+ tokenEndpoint: `${base}/multipass/api/oauth2/token`,
39
+ revocationEndpoint: `${base}/multipass/api/oauth2/revoke_token`,
40
+ clientId: application.clientId,
41
+ clientAuthentication: secret ? {
42
+ method: "client_secret_basic",
43
+ secret
44
+ } : { method: "none" },
45
+ scopes: application.scopes ?? defaultScopes,
46
+ fetch: options.fetch,
47
+ resolveSubject: (token) => identity(token).pipe(Effect.map((value) => value.userId))
48
+ });
49
+ }),
50
+ apiKey: ({ apiKey }) => identity(apiKey).pipe(Effect.map(({ userId, expiresAt }) => ({
51
+ userId,
52
+ expiresAt: expiresAt === void 0 ? void 0 : Temporal.Instant.fromEpochMilliseconds(expiresAt)
53
+ }))),
54
+ acquire: Effect.fnUntraced(function* ({ connection, serviceInstance, credential, handlers }) {
55
+ if (connection.objectType === "ExternalSessionConnection") return yield* new BackendError({
56
+ operation: "foundry.acquire",
57
+ kind: "InvalidConfiguration",
58
+ retryable: false,
59
+ message: "Foundry requires an OAuth or API-key connection."
60
+ });
61
+ const scope = yield* Effect.scope;
62
+ const web = yield* toWebEgress(handlers);
63
+ const run = Effect.runPromiseWith(yield* Effect.context());
64
+ const tokenProvider = () => run(Effect.acquireUseRelease(Effect.forkIn(credential, scope, { startImmediately: true }), Fiber.join, Fiber.interrupt));
65
+ const fetch = createFoundryFetch({
66
+ baseUrl: serviceInstance.instanceUrl,
67
+ tokenProvider,
68
+ fetch: web.fetch
69
+ });
70
+ const createWebSocket = createFoundryWebSocket({
71
+ baseUrl: serviceInstance.instanceUrl,
72
+ tokenProvider,
73
+ createWebSocket: web.createWebSocket
74
+ });
75
+ const checkTarget = (target) => Effect.try({
76
+ try: () => {
77
+ const url = new URL(target);
78
+ if (url.protocol === "wss:") url.protocol = "https:";
79
+ if (url.protocol === "ws:") url.protocol = "http:";
80
+ if (url.origin !== new URL(serviceInstance.instanceUrl).origin) throw new BackendError({
81
+ operation: "foundry.egress",
82
+ kind: "Forbidden",
83
+ retryable: false,
84
+ message: "Foundry egress target is outside the configured instance."
85
+ });
86
+ },
87
+ catch: (cause) => classifyBackendFailure("foundry.egress", cause)
88
+ });
89
+ return withHttpAuthenticationErrors({
90
+ fetch: (request) => checkTarget(request.url).pipe(Effect.andThen(Effect.tryPromise({
91
+ try: (signal) => fetch(new Request(request, { signal: AbortSignal.any([request.signal, signal]) })),
92
+ catch: (cause) => classifyBackendFailure("foundry.egress", cause)
93
+ }))),
94
+ createWebSocket: (url, protocols) => checkTarget(url).pipe(Effect.andThen(Effect.tryPromise({
95
+ try: () => createWebSocket(url, protocols),
96
+ catch: (cause) => classifyBackendFailure("foundry.egress", cause)
97
+ })))
98
+ });
99
+ })
100
+ };
101
+ }
102
+ //#endregion
103
+ export { makeFoundryServiceConnector };
104
+
105
+ //# sourceMappingURL=serviceConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceConnector.js","names":[],"sources":["../src/serviceConnector.ts"],"sourcesContent":["import {\n ConnectError,\n makeOAuthService,\n toWebEgress,\n withHttpAuthenticationErrors,\n type ServiceConnector,\n} from \"@party-stack/connect\";\nimport { createFoundryFetch, createFoundryWebSocket, getTokenDetails } from \"@party-stack/foundry-client\";\nimport { BackendError, classifyBackendFailure } from \"@party-stack/ontology-backend\";\nimport { Effect, Fiber, Schema } from \"effect\";\nimport { Temporal } from \"temporal-polyfill\";\n\n/** Reusable integration; the saved ServiceInstance supplies the Foundry stack URL. */\nexport function makeFoundryServiceConnector(\n options: {\n readonly fetch?: typeof globalThis.fetch;\n } = {}\n): ServiceConnector {\n const defaultScopes = [\n \"api:use-ontologies-read\",\n \"api:use-ontologies-write\",\n \"api:use-mediasets-read\",\n \"api:use-mediasets-write\",\n \"offline_access\",\n ];\n const identity = (token: string) =>\n Effect.try({\n try: () => getTokenDetails(token),\n catch: () =>\n new ConnectError({\n kind: \"NeedsAuthentication\",\n retryable: false,\n message: \"Foundry credentials are invalid.\",\n }),\n });\n return {\n service: \"foundry\",\n displayName: \"Foundry\",\n defaultOAuthScopes: defaultScopes,\n oauth: Effect.fnUntraced(function* ({ application, serviceInstance, values }) {\n const base = serviceInstance.instanceUrl.replace(/\\/$/, \"\");\n const secret = application.clientSecret\n ? yield* values.decrypt(Schema.String, application.clientSecret).pipe(\n Effect.mapError(\n () =>\n new ConnectError({\n kind: \"Storage\",\n retryable: false,\n message: \"OAuth client secret is unavailable.\",\n })\n )\n )\n : undefined;\n return makeOAuthService({\n issuer: `${base}/multipass/`,\n authorizationEndpoint: `${base}/multipass/api/oauth2/authorize`,\n tokenEndpoint: `${base}/multipass/api/oauth2/token`,\n revocationEndpoint: `${base}/multipass/api/oauth2/revoke_token`,\n clientId: application.clientId,\n clientAuthentication: secret ? { method: \"client_secret_basic\", secret } : { method: \"none\" },\n scopes: application.scopes ?? defaultScopes,\n fetch: options.fetch,\n resolveSubject: (token) => identity(token).pipe(Effect.map((value) => value.userId)),\n });\n }),\n apiKey: ({ apiKey }) =>\n identity(apiKey).pipe(\n Effect.map(({ userId, expiresAt }) => ({\n userId,\n expiresAt:\n expiresAt === undefined\n ? undefined\n : Temporal.Instant.fromEpochMilliseconds(expiresAt),\n }))\n ),\n acquire: Effect.fnUntraced(function* ({ connection, serviceInstance, credential, handlers }) {\n if (connection.objectType === \"ExternalSessionConnection\")\n return yield* new BackendError({\n operation: \"foundry.acquire\",\n kind: \"InvalidConfiguration\",\n retryable: false,\n message: \"Foundry requires an OAuth or API-key connection.\",\n });\n const scope = yield* Effect.scope;\n const web = yield* toWebEgress(handlers);\n const run = Effect.runPromiseWith(yield* Effect.context<never>());\n const tokenProvider = () =>\n run(\n Effect.acquireUseRelease(\n Effect.forkIn(credential, scope, { startImmediately: true }),\n Fiber.join,\n Fiber.interrupt\n )\n );\n const fetch = createFoundryFetch({\n baseUrl: serviceInstance.instanceUrl,\n tokenProvider,\n fetch: web.fetch,\n });\n const createWebSocket = createFoundryWebSocket({\n baseUrl: serviceInstance.instanceUrl,\n tokenProvider,\n createWebSocket: web.createWebSocket,\n });\n const checkTarget = (target: string | URL) =>\n Effect.try({\n try: () => {\n const url = new URL(target);\n if (url.protocol === \"wss:\") url.protocol = \"https:\";\n if (url.protocol === \"ws:\") url.protocol = \"http:\";\n if (url.origin !== new URL(serviceInstance.instanceUrl).origin)\n throw new BackendError({\n operation: \"foundry.egress\",\n kind: \"Forbidden\",\n retryable: false,\n message: \"Foundry egress target is outside the configured instance.\",\n });\n },\n catch: (cause) => classifyBackendFailure(\"foundry.egress\", cause),\n });\n return withHttpAuthenticationErrors({\n fetch: (request) =>\n checkTarget(request.url).pipe(\n Effect.andThen(\n Effect.tryPromise({\n try: (signal) =>\n fetch(\n new Request(request, {\n signal: AbortSignal.any([request.signal, signal]),\n })\n ),\n catch: (cause) => classifyBackendFailure(\"foundry.egress\", cause),\n })\n )\n ),\n createWebSocket: (url, protocols) =>\n checkTarget(url).pipe(\n Effect.andThen(\n Effect.tryPromise({\n try: () => createWebSocket(url, protocols),\n catch: (cause) => classifyBackendFailure(\"foundry.egress\", cause),\n })\n )\n ),\n });\n }),\n };\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,4BACZ,UAEI,CAAC,GACW;CAChB,MAAM,gBAAgB;EAClB;EACA;EACA;EACA;EACA;CACJ;CACA,MAAM,YAAY,UACd,OAAO,IAAI;EACP,WAAW,gBAAgB,KAAK;EAChC,aACI,IAAI,aAAa;GACb,MAAM;GACN,WAAW;GACX,SAAS;EACb,CAAC;CACT,CAAC;CACL,OAAO;EACH,SAAS;EACT,aAAa;EACb,oBAAoB;EACpB,OAAO,OAAO,WAAW,WAAW,EAAE,aAAa,iBAAiB,UAAU;GAC1E,MAAM,OAAO,gBAAgB,YAAY,QAAQ,OAAO,EAAE;GAC1D,MAAM,SAAS,YAAY,eACrB,OAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,YAAY,CAAC,CAAC,KAC3D,OAAO,eAEC,IAAI,aAAa;IACb,MAAM;IACN,WAAW;IACX,SAAS;GACb,CAAC,CACT,CACJ,IACA,KAAA;GACN,OAAO,iBAAiB;IACpB,QAAQ,GAAG,KAAK;IAChB,uBAAuB,GAAG,KAAK;IAC/B,eAAe,GAAG,KAAK;IACvB,oBAAoB,GAAG,KAAK;IAC5B,UAAU,YAAY;IACtB,sBAAsB,SAAS;KAAE,QAAQ;KAAuB;IAAO,IAAI,EAAE,QAAQ,OAAO;IAC5F,QAAQ,YAAY,UAAU;IAC9B,OAAO,QAAQ;IACf,iBAAiB,UAAU,SAAS,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;GACvF,CAAC;EACL,CAAC;EACD,SAAS,EAAE,aACP,SAAS,MAAM,CAAC,CAAC,KACb,OAAO,KAAK,EAAE,QAAQ,iBAAiB;GACnC;GACA,WACI,cAAc,KAAA,IACR,KAAA,IACA,SAAS,QAAQ,sBAAsB,SAAS;EAC9D,EAAE,CACN;EACJ,SAAS,OAAO,WAAW,WAAW,EAAE,YAAY,iBAAiB,YAAY,YAAY;GACzF,IAAI,WAAW,eAAe,6BAC1B,OAAO,OAAO,IAAI,aAAa;IAC3B,WAAW;IACX,MAAM;IACN,WAAW;IACX,SAAS;GACb,CAAC;GACL,MAAM,QAAQ,OAAO,OAAO;GAC5B,MAAM,MAAM,OAAO,YAAY,QAAQ;GACvC,MAAM,MAAM,OAAO,eAAe,OAAO,OAAO,QAAe,CAAC;GAChE,MAAM,sBACF,IACI,OAAO,kBACH,OAAO,OAAO,YAAY,OAAO,EAAE,kBAAkB,KAAK,CAAC,GAC3D,MAAM,MACN,MAAM,SACV,CACJ;GACJ,MAAM,QAAQ,mBAAmB;IAC7B,SAAS,gBAAgB;IACzB;IACA,OAAO,IAAI;GACf,CAAC;GACD,MAAM,kBAAkB,uBAAuB;IAC3C,SAAS,gBAAgB;IACzB;IACA,iBAAiB,IAAI;GACzB,CAAC;GACD,MAAM,eAAe,WACjB,OAAO,IAAI;IACP,WAAW;KACP,MAAM,MAAM,IAAI,IAAI,MAAM;KAC1B,IAAI,IAAI,aAAa,QAAQ,IAAI,WAAW;KAC5C,IAAI,IAAI,aAAa,OAAO,IAAI,WAAW;KAC3C,IAAI,IAAI,WAAW,IAAI,IAAI,gBAAgB,WAAW,CAAC,CAAC,QACpD,MAAM,IAAI,aAAa;MACnB,WAAW;MACX,MAAM;MACN,WAAW;MACX,SAAS;KACb,CAAC;IACT;IACA,QAAQ,UAAU,uBAAuB,kBAAkB,KAAK;GACpE,CAAC;GACL,OAAO,6BAA6B;IAChC,QAAQ,YACJ,YAAY,QAAQ,GAAG,CAAC,CAAC,KACrB,OAAO,QACH,OAAO,WAAW;KACd,MAAM,WACF,MACI,IAAI,QAAQ,SAAS,EACjB,QAAQ,YAAY,IAAI,CAAC,QAAQ,QAAQ,MAAM,CAAC,EACpD,CAAC,CACL;KACJ,QAAQ,UAAU,uBAAuB,kBAAkB,KAAK;IACpE,CAAC,CACL,CACJ;IACJ,kBAAkB,KAAK,cACnB,YAAY,GAAG,CAAC,CAAC,KACb,OAAO,QACH,OAAO,WAAW;KACd,WAAW,gBAAgB,KAAK,SAAS;KACzC,QAAQ,UAAU,uBAAuB,kBAAkB,KAAK;IACpE,CAAC,CACL,CACJ;GACR,CAAC;EACL,CAAC;CACL;AACJ"}
@@ -1,5 +1,5 @@
1
- import { InitialQueryBuilder } from "@tanstack/db";
2
1
  import { OntologyIR, OntologyMutator, OntologyMutatorObjects, OntologyMutatorTx } from "@party-stack/ontology";
2
+ import { InitialQueryBuilder } from "@tanstack/db";
3
3
  //#region src/stagedWrites.d.ts
4
4
  /**
5
5
  * Structural subset of Foundry's staged-write `WriteableClient`.
@@ -18,6 +18,7 @@ export interface FoundryStagedWriteClient {
18
18
  query?<T>(build: (query: InitialQueryBuilder, objects: OntologyMutatorObjects) => unknown): Promise<T>;
19
19
  }
20
20
  export interface CreateFoundryStagedWriteMutatorTxOptions {
21
+ ir: OntologyIR;
21
22
  client: FoundryStagedWriteClient;
22
23
  /**
23
24
  * Generated OSDK object type tokens, keyed by ontology API name. Required
@@ -37,6 +38,6 @@ export declare function runFoundryOntologyMutator(options: {
37
38
  args: Record<string, unknown>;
38
39
  context?: Record<string, unknown>;
39
40
  objectTypes?: Record<string, unknown>;
40
- }): Promise<void>;
41
+ }): Promise<unknown>;
41
42
  //#endregion
42
43
  //# sourceMappingURL=stagedWrites.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stagedWrites.d.ts","names":[],"sources":["../src/stagedWrites.ts"],"mappings":";;;;;;;iBAaiB;EACb,OAAO,qBAAqB,QAAQ,0BAA0B;EAC9D,OACI;IACI;IACA;KAEJ,SAAS,0BACV;EACH,OAAO;IAAU;IAAkB;MAAiC;EACpE,OAAO,GAAG,QAAQ,OAAO,qBAAqB,SAAS,qCAAqC,QAAQ;;iBAGvF;EACb,QAAQ;;;;;EAKR,cAAc;;wBA0BF,kCACZ,SAAS,2CACV;;;;;wBAuDmB,0BAA0B;EAC5C,IAAI;EACJ,QAAQ;EACR,SAAS;EACT,MAAM;EACN,UAAU;EACV,cAAc;IACd"}
1
+ {"version":3,"file":"stagedWrites.d.ts","names":[],"sources":["../src/stagedWrites.ts"],"mappings":";;;;;;;iBAeiB;EACb,OAAO,qBAAqB,QAAQ,0BAA0B;EAC9D,OACI;IACI;IACA;KAEJ,SAAS,0BACV;EACH,OAAO;IAAU;IAAkB;MAAiC;EACpE,OAAO,GAAG,QAAQ,OAAO,qBAAqB,SAAS,qCAAqC,QAAQ;;iBAGvF;EACb,IAAI;EACJ,QAAQ;;;;;EAKR,cAAc;;wBAgEF,kCACZ,SAAS,2CACV;;;;;wBAuDmB,0BAA0B;EAC5C,IAAI;EACJ,QAAQ;EACR,SAAS;EACT,MAAM;EACN,UAAU;EACV,cAAc;IACd"}
@@ -1,3 +1,5 @@
1
+ import { Predicate, Schema } from "effect";
2
+ import { resolveType } from "@party-stack/ontology-spec/utils";
1
3
  //#region src/stagedWrites.ts
2
4
  function setPath(object, path, value) {
3
5
  let target = object;
@@ -14,6 +16,30 @@ function changesToRecord(changes) {
14
16
  for (const change of changes) setPath(record, change.path, change.value);
15
17
  return record;
16
18
  }
19
+ const CiphertextHandle = Schema.Struct({ ciphertext: Schema.String.check(Schema.isPattern(/^CIPHER::[^:]+::.+::CIPHER$/u)) });
20
+ /** Foundry v2 accepts {plaintext} for new secrets and {ciphertext} for a copied value.
21
+ * Encryption happens in the ambient Foundry transaction, never in the wrapper's query path.
22
+ */
23
+ function writeProperties(ir, objectType, values) {
24
+ const definition = ir.objectTypes.find((object) => object.name === objectType);
25
+ const result = { ...values };
26
+ for (const property of definition?.properties ?? []) {
27
+ if (!Object.hasOwn(values, property.name)) continue;
28
+ let type = resolveType(ir, property.type);
29
+ while (type.kind === "optional") type = resolveType(ir, type.value.type);
30
+ if (type.kind !== "encrypted") continue;
31
+ const value = values[property.name];
32
+ if (value === void 0) continue;
33
+ if (typeof value === "string") result[property.name] = { plaintext: value };
34
+ else if (Predicate.hasProperty(value, "decrypt") && Predicate.isFunction(value.decrypt)) result[property.name] = value;
35
+ else {
36
+ const parsed = Schema.decodeUnknownOption(CiphertextHandle)(value);
37
+ if (parsed._tag === "Some") result[property.name] = { ciphertext: parsed.value.ciphertext };
38
+ else throw new TypeError("Expected plaintext or a Foundry encrypted handle for an encrypted property.");
39
+ }
40
+ }
41
+ return result;
42
+ }
17
43
  function createFoundryStagedWriteMutatorTx(options) {
18
44
  return {
19
45
  query: async (build) => {
@@ -24,13 +50,13 @@ function createFoundryStagedWriteMutatorTx(options) {
24
50
  if (typeof objectType !== "string") return;
25
51
  return {
26
52
  create: async (object) => {
27
- await options.client.create(options.objectTypes?.[objectType] ?? { $apiName: objectType }, object);
53
+ await options.client.create(options.objectTypes?.[objectType] ?? { $apiName: objectType }, writeProperties(options.ir, objectType, object));
28
54
  },
29
55
  update: async (key, changes) => {
30
56
  await options.client.update({
31
57
  $apiName: objectType,
32
58
  $primaryKey: key
33
- }, changesToRecord(changes));
59
+ }, writeProperties(options.ir, objectType, changesToRecord(changes)));
34
60
  },
35
61
  delete: async (key) => {
36
62
  await options.client.delete({
@@ -48,10 +74,11 @@ function createFoundryStagedWriteMutatorTx(options) {
48
74
  */
49
75
  async function runFoundryOntologyMutator(options) {
50
76
  const tx = createFoundryStagedWriteMutatorTx({
77
+ ir: options.ir,
51
78
  client: options.client,
52
79
  objectTypes: options.objectTypes
53
80
  });
54
- await options.mutator({
81
+ return options.mutator({
55
82
  tx,
56
83
  args: options.args,
57
84
  context: options.context ?? {}
@@ -1 +1 @@
1
- {"version":3,"file":"stagedWrites.js","names":[],"sources":["../src/stagedWrites.ts"],"sourcesContent":["import type {\n OntologyIR,\n OntologyMutator,\n OntologyMutatorObjects,\n OntologyMutatorTx,\n OntologyPropertyChange,\n} from \"@party-stack/ontology\";\nimport type { InitialQueryBuilder } from \"@tanstack/db\";\n\n/**\n * Structural subset of Foundry's staged-write `WriteableClient`.\n * Generated Foundry clients can be passed directly.\n */\nexport interface FoundryStagedWriteClient {\n create(objectType: unknown, object: Record<string, unknown>): Promise<unknown>;\n update(\n object: {\n $apiName: string;\n $primaryKey: string | number;\n },\n changes: Record<string, unknown>\n ): Promise<unknown>;\n delete(object: { $apiName: string; $primaryKey: string | number }): Promise<unknown>;\n query?<T>(build: (query: InitialQueryBuilder, objects: OntologyMutatorObjects) => unknown): Promise<T>;\n}\n\nexport interface CreateFoundryStagedWriteMutatorTxOptions {\n client: FoundryStagedWriteClient;\n /**\n * Generated OSDK object type tokens, keyed by ontology API name. Required\n * for creates when the client cannot accept an `$apiName` placeholder.\n */\n objectTypes?: Record<string, unknown>;\n}\n\nfunction setPath(object: Record<string, unknown>, path: string[], value: unknown): void {\n let target = object;\n for (const segment of path.slice(0, -1)) {\n const existing = target[segment];\n if (typeof existing !== \"object\" || existing === null || Array.isArray(existing)) {\n target[segment] = {};\n }\n target = target[segment] as Record<string, unknown>;\n }\n target[path.at(-1)!] = value;\n}\n\nfunction changesToRecord(\n changes: Record<string, unknown> | OntologyPropertyChange[]\n): Record<string, unknown> {\n if (!Array.isArray(changes)) return changes;\n const record: Record<string, unknown> = {};\n for (const change of changes) {\n setPath(record, change.path, change.value);\n }\n return record;\n}\n\nexport function createFoundryStagedWriteMutatorTx(\n options: CreateFoundryStagedWriteMutatorTxOptions\n): OntologyMutatorTx {\n return {\n query: async (build) => {\n if (!options.client.query) {\n throw new Error(\n \"Foundry staged-write mutator queries require a query adapter backed by the ambient staged-write client.\"\n );\n }\n return options.client.query(build);\n },\n mutate: new Proxy(\n {},\n {\n get: (_target, objectType) => {\n if (typeof objectType !== \"string\") {\n return undefined;\n }\n return {\n create: async (object: Record<string, unknown>) => {\n await options.client.create(\n options.objectTypes?.[objectType] ?? {\n $apiName: objectType,\n },\n object\n );\n },\n update: async (\n key: string | number,\n changes: Record<string, unknown> | OntologyPropertyChange[]\n ) => {\n await options.client.update(\n {\n $apiName: objectType,\n $primaryKey: key,\n },\n changesToRecord(changes)\n );\n },\n delete: async (key: string | number) => {\n await options.client.delete({\n $apiName: objectType,\n $primaryKey: key,\n });\n },\n };\n },\n }\n ),\n };\n}\n\n/**\n * Run a Party Stack ontology mutator inside Foundry's ambient staged-write\n * transaction. Foundry provides atomic commit/rollback and read-after-write.\n */\nexport async function runFoundryOntologyMutator(options: {\n ir: OntologyIR;\n client: FoundryStagedWriteClient;\n mutator: OntologyMutator;\n args: Record<string, unknown>;\n context?: Record<string, unknown>;\n objectTypes?: Record<string, unknown>;\n}): Promise<void> {\n const tx = createFoundryStagedWriteMutatorTx({\n client: options.client,\n objectTypes: options.objectTypes,\n });\n await options.mutator({\n tx,\n args: options.args,\n context: options.context ?? {},\n });\n}\n"],"mappings":";AAmCA,SAAS,QAAQ,QAAiC,MAAgB,OAAsB;CACpF,IAAI,SAAS;CACb,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,EAAE,GAAG;EACrC,MAAM,WAAW,OAAO;EACxB,IAAI,OAAO,aAAa,YAAY,aAAa,QAAQ,MAAM,QAAQ,QAAQ,GAC3E,OAAO,WAAW,CAAC;EAEvB,SAAS,OAAO;CACpB;CACA,OAAO,KAAK,GAAG,EAAE,KAAM;AAC3B;AAEA,SAAS,gBACL,SACuB;CACvB,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;CACpC,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,UAAU,SACjB,QAAQ,QAAQ,OAAO,MAAM,OAAO,KAAK;CAE7C,OAAO;AACX;AAEA,SAAgB,kCACZ,SACiB;CACjB,OAAO;EACH,OAAO,OAAO,UAAU;GACpB,IAAI,CAAC,QAAQ,OAAO,OAChB,MAAM,IAAI,MACN,yGACJ;GAEJ,OAAO,QAAQ,OAAO,MAAM,KAAK;EACrC;EACA,QAAQ,IAAI,MACR,CAAC,GACD,EACI,MAAM,SAAS,eAAe;GAC1B,IAAI,OAAO,eAAe,UACtB;GAEJ,OAAO;IACH,QAAQ,OAAO,WAAoC;KAC/C,MAAM,QAAQ,OAAO,OACjB,QAAQ,cAAc,eAAe,EACjC,UAAU,WACd,GACA,MACJ;IACJ;IACA,QAAQ,OACJ,KACA,YACC;KACD,MAAM,QAAQ,OAAO,OACjB;MACI,UAAU;MACV,aAAa;KACjB,GACA,gBAAgB,OAAO,CAC3B;IACJ;IACA,QAAQ,OAAO,QAAyB;KACpC,MAAM,QAAQ,OAAO,OAAO;MACxB,UAAU;MACV,aAAa;KACjB,CAAC;IACL;GACJ;EACJ,EACJ,CACJ;CACJ;AACJ;;;;;AAMA,eAAsB,0BAA0B,SAO9B;CACd,MAAM,KAAK,kCAAkC;EACzC,QAAQ,QAAQ;EAChB,aAAa,QAAQ;CACzB,CAAC;CACD,MAAM,QAAQ,QAAQ;EAClB;EACA,MAAM,QAAQ;EACd,SAAS,QAAQ,WAAW,CAAC;CACjC,CAAC;AACL"}
1
+ {"version":3,"file":"stagedWrites.js","names":[],"sources":["../src/stagedWrites.ts"],"sourcesContent":["import { resolveType } from \"@party-stack/ontology-spec/utils\";\nimport { Predicate, Schema } from \"effect\";\nimport type {\n OntologyIR,\n OntologyMutator,\n OntologyMutatorObjects,\n OntologyMutatorTx,\n OntologyPropertyChange,\n} from \"@party-stack/ontology\";\nimport type { InitialQueryBuilder } from \"@tanstack/db\";\n\n/**\n * Structural subset of Foundry's staged-write `WriteableClient`.\n * Generated Foundry clients can be passed directly.\n */\nexport interface FoundryStagedWriteClient {\n create(objectType: unknown, object: Record<string, unknown>): Promise<unknown>;\n update(\n object: {\n $apiName: string;\n $primaryKey: string | number;\n },\n changes: Record<string, unknown>\n ): Promise<unknown>;\n delete(object: { $apiName: string; $primaryKey: string | number }): Promise<unknown>;\n query?<T>(build: (query: InitialQueryBuilder, objects: OntologyMutatorObjects) => unknown): Promise<T>;\n}\n\nexport interface CreateFoundryStagedWriteMutatorTxOptions {\n ir: OntologyIR;\n client: FoundryStagedWriteClient;\n /**\n * Generated OSDK object type tokens, keyed by ontology API name. Required\n * for creates when the client cannot accept an `$apiName` placeholder.\n */\n objectTypes?: Record<string, unknown>;\n}\n\nfunction setPath(object: Record<string, unknown>, path: string[], value: unknown): void {\n let target = object;\n for (const segment of path.slice(0, -1)) {\n const existing = target[segment];\n if (typeof existing !== \"object\" || existing === null || Array.isArray(existing)) {\n target[segment] = {};\n }\n target = target[segment] as Record<string, unknown>;\n }\n target[path.at(-1)!] = value;\n}\n\nfunction changesToRecord(\n changes: Record<string, unknown> | OntologyPropertyChange[]\n): Record<string, unknown> {\n if (!Array.isArray(changes)) return changes;\n const record: Record<string, unknown> = {};\n for (const change of changes) {\n setPath(record, change.path, change.value);\n }\n return record;\n}\n\nconst CiphertextHandle = Schema.Struct({\n ciphertext: Schema.String.check(Schema.isPattern(/^CIPHER::[^:]+::.+::CIPHER$/u)),\n});\n\n/** Foundry v2 accepts {plaintext} for new secrets and {ciphertext} for a copied value.\n * Encryption happens in the ambient Foundry transaction, never in the wrapper's query path.\n */\nfunction writeProperties(\n ir: OntologyIR,\n objectType: string,\n values: Record<string, unknown>\n): Record<string, unknown> {\n const definition = ir.objectTypes.find((object) => object.name === objectType);\n const result = { ...values };\n for (const property of definition?.properties ?? []) {\n if (!Object.hasOwn(values, property.name)) continue;\n let type = resolveType(ir, property.type);\n while (type.kind === \"optional\") type = resolveType(ir, type.value.type);\n if (type.kind !== \"encrypted\") continue;\n const value = values[property.name];\n if (value === undefined) continue;\n if (typeof value === \"string\") result[property.name] = { plaintext: value };\n else if (Predicate.hasProperty(value, \"decrypt\") && Predicate.isFunction(value.decrypt)) {\n // Real OSDK CipherText objects are normalized by WriteableClient itself; never applyAction decrypt.\n result[property.name] = value;\n } else {\n // Portable handles are not OSDK CipherText instances; convert them explicitly.\n const parsed = Schema.decodeUnknownOption(CiphertextHandle)(value);\n if (parsed._tag === \"Some\") result[property.name] = { ciphertext: parsed.value.ciphertext };\n else\n throw new TypeError(\n \"Expected plaintext or a Foundry encrypted handle for an encrypted property.\"\n );\n }\n }\n return result;\n}\n\nexport function createFoundryStagedWriteMutatorTx(\n options: CreateFoundryStagedWriteMutatorTxOptions\n): OntologyMutatorTx {\n return {\n query: async (build) => {\n if (!options.client.query) {\n throw new Error(\n \"Foundry staged-write mutator queries require a query adapter backed by the ambient staged-write client.\"\n );\n }\n return options.client.query(build);\n },\n mutate: new Proxy(\n {},\n {\n get: (_target, objectType) => {\n if (typeof objectType !== \"string\") {\n return undefined;\n }\n return {\n create: async (object: Record<string, unknown>) => {\n await options.client.create(\n options.objectTypes?.[objectType] ?? {\n $apiName: objectType,\n },\n writeProperties(options.ir, objectType, object)\n );\n },\n update: async (\n key: string | number,\n changes: Record<string, unknown> | OntologyPropertyChange[]\n ) => {\n await options.client.update(\n {\n $apiName: objectType,\n $primaryKey: key,\n },\n writeProperties(options.ir, objectType, changesToRecord(changes))\n );\n },\n delete: async (key: string | number) => {\n await options.client.delete({\n $apiName: objectType,\n $primaryKey: key,\n });\n },\n };\n },\n }\n ),\n };\n}\n\n/**\n * Run a Party Stack ontology mutator inside Foundry's ambient staged-write\n * transaction. Foundry provides atomic commit/rollback and read-after-write.\n */\nexport async function runFoundryOntologyMutator(options: {\n ir: OntologyIR;\n client: FoundryStagedWriteClient;\n mutator: OntologyMutator;\n args: Record<string, unknown>;\n context?: Record<string, unknown>;\n objectTypes?: Record<string, unknown>;\n}): Promise<unknown> {\n const tx = createFoundryStagedWriteMutatorTx({\n ir: options.ir,\n client: options.client,\n objectTypes: options.objectTypes,\n });\n return options.mutator({\n tx,\n args: options.args,\n context: options.context ?? {},\n });\n}\n"],"mappings":";;;AAsCA,SAAS,QAAQ,QAAiC,MAAgB,OAAsB;CACpF,IAAI,SAAS;CACb,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,EAAE,GAAG;EACrC,MAAM,WAAW,OAAO;EACxB,IAAI,OAAO,aAAa,YAAY,aAAa,QAAQ,MAAM,QAAQ,QAAQ,GAC3E,OAAO,WAAW,CAAC;EAEvB,SAAS,OAAO;CACpB;CACA,OAAO,KAAK,GAAG,EAAE,KAAM;AAC3B;AAEA,SAAS,gBACL,SACuB;CACvB,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;CACpC,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,UAAU,SACjB,QAAQ,QAAQ,OAAO,MAAM,OAAO,KAAK;CAE7C,OAAO;AACX;AAEA,MAAM,mBAAmB,OAAO,OAAO,EACnC,YAAY,OAAO,OAAO,MAAM,OAAO,UAAU,8BAA8B,CAAC,EACpF,CAAC;;;;AAKD,SAAS,gBACL,IACA,YACA,QACuB;CACvB,MAAM,aAAa,GAAG,YAAY,MAAM,WAAW,OAAO,SAAS,UAAU;CAC7E,MAAM,SAAS,EAAE,GAAG,OAAO;CAC3B,KAAK,MAAM,YAAY,YAAY,cAAc,CAAC,GAAG;EACjD,IAAI,CAAC,OAAO,OAAO,QAAQ,SAAS,IAAI,GAAG;EAC3C,IAAI,OAAO,YAAY,IAAI,SAAS,IAAI;EACxC,OAAO,KAAK,SAAS,YAAY,OAAO,YAAY,IAAI,KAAK,MAAM,IAAI;EACvE,IAAI,KAAK,SAAS,aAAa;EAC/B,MAAM,QAAQ,OAAO,SAAS;EAC9B,IAAI,UAAU,KAAA,GAAW;EACzB,IAAI,OAAO,UAAU,UAAU,OAAO,SAAS,QAAQ,EAAE,WAAW,MAAM;OACrE,IAAI,UAAU,YAAY,OAAO,SAAS,KAAK,UAAU,WAAW,MAAM,OAAO,GAElF,OAAO,SAAS,QAAQ;OACrB;GAEH,MAAM,SAAS,OAAO,oBAAoB,gBAAgB,CAAC,CAAC,KAAK;GACjE,IAAI,OAAO,SAAS,QAAQ,OAAO,SAAS,QAAQ,EAAE,YAAY,OAAO,MAAM,WAAW;QAEtF,MAAM,IAAI,UACN,6EACJ;EACR;CACJ;CACA,OAAO;AACX;AAEA,SAAgB,kCACZ,SACiB;CACjB,OAAO;EACH,OAAO,OAAO,UAAU;GACpB,IAAI,CAAC,QAAQ,OAAO,OAChB,MAAM,IAAI,MACN,yGACJ;GAEJ,OAAO,QAAQ,OAAO,MAAM,KAAK;EACrC;EACA,QAAQ,IAAI,MACR,CAAC,GACD,EACI,MAAM,SAAS,eAAe;GAC1B,IAAI,OAAO,eAAe,UACtB;GAEJ,OAAO;IACH,QAAQ,OAAO,WAAoC;KAC/C,MAAM,QAAQ,OAAO,OACjB,QAAQ,cAAc,eAAe,EACjC,UAAU,WACd,GACA,gBAAgB,QAAQ,IAAI,YAAY,MAAM,CAClD;IACJ;IACA,QAAQ,OACJ,KACA,YACC;KACD,MAAM,QAAQ,OAAO,OACjB;MACI,UAAU;MACV,aAAa;KACjB,GACA,gBAAgB,QAAQ,IAAI,YAAY,gBAAgB,OAAO,CAAC,CACpE;IACJ;IACA,QAAQ,OAAO,QAAyB;KACpC,MAAM,QAAQ,OAAO,OAAO;MACxB,UAAU;MACV,aAAa;KACjB,CAAC;IACL;GACJ;EACJ,EACJ,CACJ;CACJ;AACJ;;;;;AAMA,eAAsB,0BAA0B,SAO3B;CACjB,MAAM,KAAK,kCAAkC;EACzC,IAAI,QAAQ;EACZ,QAAQ,QAAQ;EAChB,aAAa,QAAQ;CACzB,CAAC;CACD,OAAO,QAAQ,QAAQ;EACnB;EACA,MAAM,QAAQ;EACd,SAAS,QAAQ,WAAW,CAAC;CACjC,CAAC;AACL"}