@keboola/api-client 54.0.0 → 55.0.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 (114) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +1 -1
  3. package/dist/{componentId-Cps6WBy1.js → componentId-Ba4gsJ9O.js} +3 -1
  4. package/dist/componentId-Ba4gsJ9O.js.map +1 -0
  5. package/dist/{componentId-_tRhEv6W.cjs → componentId-Ba_1Gv_A.cjs} +3 -1
  6. package/dist/componentId-Ba_1Gv_A.cjs.map +1 -0
  7. package/dist/constants/index.cjs +3 -2
  8. package/dist/constants/index.d.cts +2 -2
  9. package/dist/constants/index.d.ts +2 -2
  10. package/dist/constants/index.js +3 -3
  11. package/dist/{constants-DLPkpnGv.js → constants-HccvU5kx.js} +9 -2
  12. package/dist/constants-HccvU5kx.js.map +1 -0
  13. package/dist/{constants-Day8CU5i.cjs → constants-V9hAyPTo.cjs} +14 -1
  14. package/dist/constants-V9hAyPTo.cjs.map +1 -0
  15. package/dist/encryption/index.d.cts +1 -1
  16. package/dist/encryption/index.d.ts +1 -1
  17. package/dist/encryption/types.d.cts +1 -1
  18. package/dist/encryption/types.d.ts +1 -1
  19. package/dist/{index-DX7qciZA.d.cts → index-BE6qM0vu.d.cts} +526 -30
  20. package/dist/{index-DCfumWzq.d.ts → index-BGsP2QBc.d.ts} +2 -2
  21. package/dist/{index-Df30jjpZ.d.ts → index-CQPs3hrp.d.ts} +15 -38
  22. package/dist/{index-B04rWq_0.d.cts → index-CWowDl63.d.cts} +2 -2
  23. package/dist/{index-Cd0naVic.d.cts → index-CYk7Aa8u.d.cts} +11 -2
  24. package/dist/{index-BtvWJBYh.d.cts → index-CmyFWQXn.d.cts} +15 -38
  25. package/dist/{index-DbStyQKc.d.ts → index-D3hWR_e4.d.ts} +11 -2
  26. package/dist/{index-DzqHh0lE.d.ts → index-DeWeUUfE.d.ts} +526 -30
  27. package/dist/index.cjs +8 -13
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +8 -13
  32. package/dist/index.js.map +1 -1
  33. package/dist/management/index.cjs +1 -1
  34. package/dist/management/index.d.cts +1 -1
  35. package/dist/management/index.d.ts +1 -1
  36. package/dist/management/index.js +1 -1
  37. package/dist/management/types.d.cts +2 -2
  38. package/dist/management/types.d.ts +2 -2
  39. package/dist/{management-BAfg8BmK.js → management-BlMQnPNS.js} +10 -16
  40. package/dist/management-BlMQnPNS.js.map +1 -0
  41. package/dist/{management-BuNIc7Mr.cjs → management-dIMrTTpI.cjs} +10 -16
  42. package/dist/management-dIMrTTpI.cjs.map +1 -0
  43. package/dist/oauth/index.cjs +1 -1
  44. package/dist/oauth/index.d.cts +8 -1
  45. package/dist/oauth/index.d.ts +8 -1
  46. package/dist/oauth/index.js +1 -1
  47. package/dist/oauth/types.d.cts +2 -2
  48. package/dist/oauth/types.d.ts +2 -2
  49. package/dist/{oauth-CXcrilOp.cjs → oauth-CEW2AvDV.cjs} +9 -1
  50. package/dist/{oauth-CXcrilOp.cjs.map → oauth-CEW2AvDV.cjs.map} +1 -1
  51. package/dist/{oauth-Ci0qeaS2.js → oauth-Fri6IthS.js} +9 -1
  52. package/dist/{oauth-Ci0qeaS2.js.map → oauth-Fri6IthS.js.map} +1 -1
  53. package/dist/queryService/index.d.cts +1 -1
  54. package/dist/queryService/index.d.ts +1 -1
  55. package/dist/queryService/types.d.cts +1 -1
  56. package/dist/queryService/types.d.ts +1 -1
  57. package/dist/queue/index.d.cts +1 -1
  58. package/dist/queue/index.d.ts +1 -1
  59. package/dist/sdk/configurations/index.cjs +47 -2
  60. package/dist/sdk/configurations/index.cjs.map +1 -1
  61. package/dist/sdk/configurations/index.d.cts +230 -2
  62. package/dist/sdk/configurations/index.d.ts +230 -2
  63. package/dist/sdk/configurations/index.js +47 -2
  64. package/dist/sdk/configurations/index.js.map +1 -1
  65. package/dist/sdk/dataAppServer/index.cjs +1 -1
  66. package/dist/sdk/dataAppServer/index.cjs.map +1 -1
  67. package/dist/sdk/dataAppServer/index.d.cts +1 -1
  68. package/dist/sdk/dataAppServer/index.d.ts +1 -1
  69. package/dist/sdk/dataAppServer/index.js +1 -1
  70. package/dist/sdk/dataAppServer/index.js.map +1 -1
  71. package/dist/sdk/queryService/index.d.cts +1 -1
  72. package/dist/sdk/queryService/index.d.ts +1 -1
  73. package/dist/sdk/securityPolicy/index.cjs +13 -3
  74. package/dist/sdk/securityPolicy/index.cjs.map +1 -1
  75. package/dist/sdk/securityPolicy/index.d.cts +11 -1
  76. package/dist/sdk/securityPolicy/index.d.ts +11 -1
  77. package/dist/sdk/securityPolicy/index.js +12 -4
  78. package/dist/sdk/securityPolicy/index.js.map +1 -1
  79. package/dist/sdk/vault/index.cjs +3 -12
  80. package/dist/sdk/vault/index.cjs.map +1 -1
  81. package/dist/sdk/vault/index.d.cts +1 -1
  82. package/dist/sdk/vault/index.d.ts +1 -1
  83. package/dist/sdk/vault/index.js +3 -12
  84. package/dist/sdk/vault/index.js.map +1 -1
  85. package/dist/storage/index.cjs +1 -1
  86. package/dist/storage/index.d.cts +2 -2
  87. package/dist/storage/index.d.ts +2 -2
  88. package/dist/storage/index.js +1 -1
  89. package/dist/storage/types.d.cts +2 -2
  90. package/dist/storage/types.d.ts +2 -2
  91. package/dist/{storage-BMrYlyLB.cjs → storage-BL-TfHp8.cjs} +2 -2
  92. package/dist/storage-BL-TfHp8.cjs.map +1 -0
  93. package/dist/{storage--2FvvLAw.js → storage-DEJN8sw-.js} +2 -2
  94. package/dist/storage-DEJN8sw-.js.map +1 -0
  95. package/dist/syncActions/index.cjs +1 -1
  96. package/dist/syncActions/index.js +1 -1
  97. package/dist/{syncActions-CR7xvuIv.cjs → syncActions-B9JTiSao.cjs} +2 -2
  98. package/dist/{syncActions-CR7xvuIv.cjs.map → syncActions-B9JTiSao.cjs.map} +1 -1
  99. package/dist/{syncActions-CU4cIGRf.js → syncActions-W98Jme2Z.js} +2 -2
  100. package/dist/{syncActions-CU4cIGRf.js.map → syncActions-W98Jme2Z.js.map} +1 -1
  101. package/dist/{types-B7FKoyfy.d.cts → types-Bwvss_gW.d.cts} +819 -388
  102. package/dist/{types-CaBcgsT2.d.cts → types-DMhgKHCP.d.cts} +221 -54
  103. package/dist/{types-COb2O9c1.d.ts → types-J_dgwMjP.d.ts} +819 -388
  104. package/dist/{types-DFcj9YyQ.d.ts → types-p_lWvuQJ.d.ts} +221 -54
  105. package/package.json +3 -3
  106. package/surface/management.md +25 -25
  107. package/dist/componentId-Cps6WBy1.js.map +0 -1
  108. package/dist/componentId-_tRhEv6W.cjs.map +0 -1
  109. package/dist/constants-DLPkpnGv.js.map +0 -1
  110. package/dist/constants-Day8CU5i.cjs.map +0 -1
  111. package/dist/management-BAfg8BmK.js.map +0 -1
  112. package/dist/management-BuNIc7Mr.cjs.map +0 -1
  113. package/dist/storage--2FvvLAw.js.map +0 -1
  114. package/dist/storage-BMrYlyLB.cjs.map +0 -1
@@ -110,6 +110,15 @@ const securityPolicyReadSchema = require_metaObject.metastoreObjectReadSchema(po
110
110
  const DEFAULT_BRANCH = "main";
111
111
  /** The rule schema Kai writes; a policy created under another version keeps its own. */
112
112
  const CURRENT_SCHEMA_VERSION = "1.2.0";
113
+ /** A policy stored under an older rule schema: the metastore refuses current rules for it. */
114
+ const isLegacySecurityPolicy = (meta) => meta.schemaVersion !== void 0 && meta.schemaVersion !== CURRENT_SCHEMA_VERSION;
115
+ const onDefaultBranch = (policy) => policy.meta.branch === void 0 || policy.meta.branch === DEFAULT_BRANCH;
116
+ /**
117
+ * Whether `projectId` owns the policy on `main`: a create for its table replaces it.
118
+ *
119
+ * - Others' policies on the table are never replaced; they stack with the project's own.
120
+ */
121
+ const isReplaceableSecurityPolicy = (policy, projectId) => policy.meta.projectId === projectId && onDefaultBranch(policy);
113
122
  /** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */
114
123
  var SecurityPolicyAmbiguousError = class extends Error {
115
124
  policyType;
@@ -211,7 +220,6 @@ const parsePolicies = (policyType, data) => {
211
220
  };
212
221
  const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
213
222
  const isOwn = (policy) => policy.meta.projectId === projectId;
214
- const onDefaultBranch = (policy) => policy.meta.branch === void 0 || policy.meta.branch === DEFAULT_BRANCH;
215
223
  /**
216
224
  * Every policy of one type the caller can read.
217
225
  *
@@ -268,7 +276,7 @@ const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
268
276
  known = listed.policies;
269
277
  }
270
278
  const onTable = known.filter((policy) => policy.data.table === table && onDefaultBranch(policy));
271
- const owned = onTable.filter(isOwn);
279
+ const owned = onTable.filter((policy) => isReplaceableSecurityPolicy(policy, projectId));
272
280
  const otherPolicyUuids = onTable.filter((policy) => !isOwn(policy)).map((policy) => policy.uuid);
273
281
  const current = options.uuid === void 0 ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);
274
282
  if (options.uuid !== void 0 && current === void 0) throw new SecurityPolicyNotFoundError({
@@ -282,7 +290,7 @@ const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
282
290
  uuids: owned.map((policy) => policy.uuid)
283
291
  });
284
292
  if (current) {
285
- if (current.meta.schemaVersion !== void 0 && current.meta.schemaVersion !== CURRENT_SCHEMA_VERSION) throw new SecurityPolicyLegacyError({
293
+ if (isLegacySecurityPolicy(current.meta)) throw new SecurityPolicyLegacyError({
286
294
  policyType,
287
295
  uuid: current.uuid,
288
296
  schemaVersion: current.meta.schemaVersion
@@ -350,6 +358,8 @@ exports.SecurityPolicyNotFoundError = SecurityPolicyNotFoundError;
350
358
  exports.SecurityPolicyUnreadableError = SecurityPolicyUnreadableError;
351
359
  exports.clsPolicySchema = clsPolicySchema;
352
360
  exports.createSecurityPolicySdk = createSecurityPolicySdk;
361
+ exports.isLegacySecurityPolicy = isLegacySecurityPolicy;
362
+ exports.isReplaceableSecurityPolicy = isReplaceableSecurityPolicy;
353
363
  exports.rlsPolicySchema = rlsPolicySchema;
354
364
 
355
365
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["z","z","metastoreObjectReadSchema","parseOrThrow","z","formatValidationIssues","isApiError","metastoreErrorMessage"],"sources":["../../../src/sdks/securityPolicy/vocabulary.ts","../../../src/sdks/securityPolicy/schemas.ts","../../../src/sdks/securityPolicy/readSchemas.ts","../../../src/sdks/securityPolicy/securityPolicySdk.ts"],"sourcesContent":["/**\n * The metastore's row- and column-level security vocabulary, schema version 1.2.0.\n *\n * - Each list is the one place a value is added; the types in `./types` derive from it.\n */\n\nexport const SECURITY_POLICY_TYPES = ['rls-policy', 'cls-policy'] as const;\n\nexport const POLICY_SQL_DIALECTS = ['snowflake', 'bigquery'] as const;\n\nexport const RLS_COMPARISON_OPS = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const;\n\nexport const RLS_LIST_OPS = ['in', 'not_in'] as const;\n\nexport const RLS_NULL_OPS = ['is_null', 'is_not_null'] as const;\n","import { z } from 'zod';\n\nimport type { ClsPolicyData, RlsCondition, RlsPolicyData } from './types';\nimport { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS } from './vocabulary';\n\n/** A `<bucket>.<table>` key; also the policy's metastore name. */\nconst POLICY_TABLE_PATTERN = /^[A-Za-z0-9_.-]+\\.[A-Za-z0-9_-]+$/;\n\n/** Columns are SQL identifiers that cannot be parameterised, so this pattern is the boundary. */\nconst POLICY_COLUMN_PATTERN = /^[A-Za-z0-9_]+$/;\n\n/** A reader selector `<idp>|<sub>`: the identity provider's issuer, a `|`, the user's `sub`. */\nconst POLICY_SUBJECT_PATTERN = /^[^|\\s]+\\|\\S.*$/;\n\n/**\n * Write validators for untrusted policy input, mirroring metastore schema 1.2.0.\n *\n * - Strict: an unknown key fails, as `additionalProperties: false` does in the metastore.\n * - The identifier patterns are the boundary: `table` and `column` reach SQL unparameterised.\n * - Stricter than the metastore on purpose: a `value` is a string, number, boolean or null, and\n * `values` holds the same; the metastore also lets an arbitrary JSON value through.\n * - The metastore stays the authority; this reports the first problem in words the model can act on.\n */\n\nconst column = z.string().regex(POLICY_COLUMN_PATTERN, 'column must match [A-Za-z0-9_]+');\n\nconst literal = z.union([z.string(), z.number(), z.boolean(), z.null()]);\n\nconst identityEmail = z.strictObject({ $identity: z.literal('email') });\nconst identityGroups = z.strictObject({ $identity: z.literal('groups') });\n\nconst rlsCondition: z.ZodType<RlsCondition> = z.lazy(() =>\n z.union([\n z.strictObject({ true: z.literal(true) }),\n z.strictObject({ false: z.literal(true) }),\n z.strictObject({ and: z.array(rlsCondition).min(2) }),\n z.strictObject({ or: z.array(rlsCondition).min(2) }),\n z.strictObject({\n column,\n op: z.enum(RLS_COMPARISON_OPS),\n value: z.union([literal, identityEmail]),\n }),\n z.strictObject({\n column,\n op: z.enum(RLS_LIST_OPS),\n values: z.union([z.array(literal).min(1), identityGroups]),\n }),\n z.strictObject({ column, op: z.enum(RLS_NULL_OPS) }),\n ]),\n);\n\n/** `[\"*\"]` is everyone and must be the only entry. */\nconst selectorList = (item: z.ZodType<string>) =>\n z\n .array(item)\n .min(1)\n .refine((list) => !list.includes('*') || list.length === 1, {\n message: '\"*\" must be the only entry',\n });\n\nconst subjects = selectorList(\n z.union([\n z.literal('*'),\n z\n .string()\n .max(1024)\n .regex(POLICY_SUBJECT_PATTERN, 'a subject is \"<idp>|<sub>\", never an email'),\n ]),\n);\nconst groups = selectorList(z.string().min(1));\n\n/** A rule selects readers by exactly one of `subjects` or `groups`, then carries `shape`. */\nconst rule = <Shape extends z.ZodRawShape>(shape: Shape) =>\n z.union([z.strictObject({ subjects, ...shape }), z.strictObject({ groups, ...shape })]);\n\nconst table = z.string().regex(POLICY_TABLE_PATTERN, 'table must be \"<bucket>.<table>\"');\nconst dialect = z.enum(POLICY_SQL_DIALECTS).optional();\n\nexport const rlsPolicySchema: z.ZodType<RlsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ condition: rlsCondition })).min(1),\n default: rlsCondition.optional(),\n});\n\nexport const clsPolicySchema: z.ZodType<ClsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ visible_columns: z.array(column).min(1) })).min(1),\n});\n","import { z } from 'zod';\n\nimport { metastoreObjectReadSchema } from '../../clients/metastore/metaObject';\n\nimport type { SecurityPolicyReadData } from './types';\nimport { POLICY_SQL_DIALECTS } from './vocabulary';\n\n/**\n * What a read of the metastore may hand back for a policy.\n *\n * - `looseObject`: fields the metastore adds still reach callers.\n * - An unknown `dialect` reads as absent; a missing `table` or `rules` drops the object.\n * - The envelope is the metastore's own, shared with every object family.\n */\n\nconst policyReadDataSchema: z.ZodType<SecurityPolicyReadData, unknown> = z.looseObject({\n table: z.string(),\n dialect: z.enum(POLICY_SQL_DIALECTS).optional().catch(undefined),\n rules: z.array(z.record(z.string(), z.unknown())),\n default: z.unknown().optional(),\n});\n\nexport const securityPolicyReadSchema = metastoreObjectReadSchema(policyReadDataSchema);\n","import { z } from 'zod';\n\nimport { metastoreErrorMessage } from '../../clients/metastore/errorMessage';\nimport { formatValidationIssues, parseOrThrow } from '../../errors';\nimport { isApiError } from '../../fetchClient';\n\nimport { securityPolicyReadSchema } from './readSchemas';\nimport type {\n MetastoreClient,\n SecurityPolicy,\n SecurityPolicyDataMap,\n SecurityPolicyType,\n} from './types';\n\nconst DEFAULT_BRANCH = 'main';\n\n/** The rule schema Kai writes; a policy created under another version keeps its own. */\nconst CURRENT_SCHEMA_VERSION = '1.2.0';\n\n/** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */\nexport class SecurityPolicyAmbiguousError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuids: string[];\n\n constructor({\n policyType,\n table,\n uuids,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuids: string[];\n }) {\n super(\n `The project has ${uuids.length} ${policyType} policies for table '${table}' ` +\n `(${uuids.join(', ')}); pass the uuid of the one to replace.`,\n );\n this.name = 'SecurityPolicyAmbiguousError';\n this.policyType = policyType;\n this.table = table;\n this.uuids = uuids;\n }\n}\n\n/**\n * Thrown by `deletePolicy` on a `409`: other objects still reference the policy, nothing was deleted.\n *\n * - The metastore does not name the referencing objects, so none is reported here.\n */\nexport class SecurityPolicyInUseError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n\n constructor({\n policyType,\n uuid,\n reason,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n reason?: string;\n }) {\n super(reason ?? `The ${policyType} policy '${uuid}' is still bound and was not deleted.`);\n this.name = 'SecurityPolicyInUseError';\n this.policyType = policyType;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when some policy of the type could not be read.\n *\n * - Whether that policy governs the table is unknown, and a second policy on it would AND with it.\n */\nexport class SecurityPolicyUnreadableError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly count: number;\n\n constructor({ policyType, count }: { policyType: SecurityPolicyType; count: number }) {\n super(\n `${count} ${policyType} polic${count === 1 ? 'y' : 'ies'} of the project could not be read, ` +\n `so it is unknown whether the table already has one; nothing was written.`,\n );\n this.name = 'SecurityPolicyUnreadableError';\n this.policyType = policyType;\n this.count = count;\n }\n}\n\n/** The caller named a policy by `uuid` that the project does not own for the table. */\nexport class SecurityPolicyNotFoundError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuid: string;\n\n constructor({\n policyType,\n table,\n uuid,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuid: string;\n }) {\n super(`The project owns no ${policyType} '${uuid}' for table '${table}'.`);\n this.name = 'SecurityPolicyNotFoundError';\n this.policyType = policyType;\n this.table = table;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when the policy to replace was written under an older schema.\n *\n * - The metastore validates a write against the schema version the object already has, so 1.2.0\n * `subjects` on a 1.0.0 or 1.1.0 policy (`principal`, `principals`) fail with a 422.\n * - Nothing was written. Delete the policy and create it again; a policy an app binds cannot be deleted.\n */\nexport class SecurityPolicyLegacyError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n readonly schemaVersion: string;\n\n constructor({\n policyType,\n uuid,\n schemaVersion,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n schemaVersion: string;\n }) {\n super(\n `The ${policyType} '${uuid}' is on schema ${schemaVersion}, not ${CURRENT_SCHEMA_VERSION}, ` +\n `and the metastore keeps a policy on the schema it was created with; nothing was written.`,\n );\n this.name = 'SecurityPolicyLegacyError';\n this.policyType = policyType;\n this.uuid = uuid;\n this.schemaVersion = schemaVersion;\n }\n}\n\ntype Options = {\n metastoreClient: MetastoreClient;\n /** The project the caller writes as; a policy it owns carries this in `meta.projectId`. */\n projectId: number;\n};\n\n/**\n * The policies in a metastore collection response.\n *\n * - A malformed element is dropped, logged without its payload and counted in `unreadable`.\n * - A response that is not a collection throws.\n */\nconst parsePolicies = (\n policyType: SecurityPolicyType,\n data: unknown,\n): { policies: SecurityPolicy[]; unreadable: number } => {\n const items = parseOrThrow(z.array(z.unknown()), data);\n\n const policies: SecurityPolicy[] = [];\n let unreadable = 0;\n for (const item of items) {\n const result = securityPolicyReadSchema.safeParse(item);\n if (result.success) {\n policies.push(result.data);\n continue;\n }\n\n unreadable += 1;\n // Never log the payload: it holds customer identities.\n console.warn(\n `securityPolicySdk: dropped a ${policyType} from the metastore response, it does not ` +\n `match its declared shape`,\n formatValidationIssues(result.error.issues),\n );\n }\n return { policies, unreadable };\n};\n\nexport const createSecurityPolicySdk = ({ metastoreClient, projectId }: Options) => {\n const isOwn = (policy: SecurityPolicy) => policy.meta.projectId === projectId;\n\n // A list without `branch` returns every branch, and a create always writes `main`: a policy on\n // another branch is neither the one to replace nor one that stacks with it.\n const onDefaultBranch = (policy: SecurityPolicy) =>\n policy.meta.branch === undefined || policy.meta.branch === DEFAULT_BRANCH;\n\n /**\n * Every policy of one type the caller can read.\n *\n * - A project admin reads only the policies the project owns. An organization admin also reads\n * organization-scope policies and ones shared into the project; `meta.projectId` tells them apart.\n * - A malformed element is dropped and logged; `listPoliciesWithUnreadable` also counts them.\n * - A response that is not a collection throws.\n */\n const listPoliciesWithUnreadable = async (\n policyType: SecurityPolicyType,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjects(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data);\n };\n\n const listPolicies = async (policyType: SecurityPolicyType, signal?: AbortSignal) =>\n (await listPoliciesWithUnreadable(policyType, signal)).policies;\n\n /**\n * One policy by UUID, from any project or scope the caller can read.\n *\n * - A policy that does not parse throws a `ValidationError` rather than reading as missing.\n * - `404`: no such policy, or the caller cannot see it.\n */\n const getPolicy = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObject(\n { objectType: policyType, UUID: policyUUID },\n signal,\n );\n return parseOrThrow(securityPolicyReadSchema, response.data);\n };\n\n /**\n * Every revision of one policy, newest first.\n *\n * - The metastore lists revisions per object type only, so this reads them all and keeps the policy's.\n * - A revision that does not parse is dropped and logged, as in `listPolicies`.\n */\n const listRevisions = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjectRevisions(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data)\n .policies.filter((revision) => revision.uuid === policyUUID)\n .sort((a, b) => (b.meta.revision ?? 0) - (a.meta.revision ?? 0));\n };\n\n /**\n * Creates the policy for its table, or replaces the one the project owns for it (a PUT).\n *\n * - Found by table on `main`; several owned ones throw `SecurityPolicyAmbiguousError`, `uuid` picks one.\n * - Others' policies are never replaced and come back in `otherPolicyUuids`; no scope is sent.\n * - Refused, nothing written: an unreadable policy of the type, or a legacy-schema one to replace.\n * - `existing`: a batch shares one listing, checks `unreadable` itself and must not repeat a table.\n */\n const upsertPolicy = async <T extends SecurityPolicyType>(\n policyType: T,\n data: SecurityPolicyDataMap[T],\n options: { existing?: SecurityPolicy[]; uuid?: string } = {},\n ): Promise<{ action: 'created' | 'updated'; uuid: string; otherPolicyUuids: string[] }> => {\n const { table } = data;\n let known = options.existing;\n if (known === undefined) {\n const listed = await listPoliciesWithUnreadable(policyType);\n if (listed.unreadable > 0) {\n throw new SecurityPolicyUnreadableError({ policyType, count: listed.unreadable });\n }\n known = listed.policies;\n }\n const onTable = known.filter(\n (policy) => policy.data.table === table && onDefaultBranch(policy),\n );\n const owned = onTable.filter(isOwn);\n const otherPolicyUuids = onTable\n .filter((policy) => !isOwn(policy))\n .map((policy) => policy.uuid);\n\n const current =\n options.uuid === undefined ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);\n if (options.uuid !== undefined && current === undefined) {\n throw new SecurityPolicyNotFoundError({ policyType, table, uuid: options.uuid });\n }\n if (options.uuid === undefined && owned.length > 1) {\n throw new SecurityPolicyAmbiguousError({\n policyType,\n table,\n uuids: owned.map((policy) => policy.uuid),\n });\n }\n\n if (current) {\n if (\n current.meta.schemaVersion !== undefined &&\n current.meta.schemaVersion !== CURRENT_SCHEMA_VERSION\n ) {\n throw new SecurityPolicyLegacyError({\n policyType,\n uuid: current.uuid,\n schemaVersion: current.meta.schemaVersion,\n });\n }\n await metastoreClient.repository.replaceMetaObject({\n objectType: policyType,\n UUID: current.uuid,\n data,\n name: current.meta.name ?? table,\n });\n return { action: 'updated', uuid: current.uuid, otherPolicyUuids };\n }\n\n const created = await metastoreClient.repository.createMetaObject({\n objectType: policyType,\n data,\n branch: DEFAULT_BRANCH,\n name: table,\n });\n return { action: 'created', uuid: created.data.id, otherPolicyUuids };\n };\n\n /**\n * - `SecurityPolicyInUseError` (`409`): other objects still reference the policy; nothing was deleted.\n * - `404`: no such policy, or it was already deleted.\n */\n const deletePolicy = async (policyType: SecurityPolicyType, policyUUID: string) => {\n try {\n await metastoreClient.repository.deleteMetaObject({\n objectType: policyType,\n UUID: policyUUID,\n });\n } catch (error) {\n if (!isApiError(error) || error.response.status !== 409) throw error;\n throw new SecurityPolicyInUseError({\n policyType,\n uuid: policyUUID,\n reason: metastoreErrorMessage(error.data),\n });\n }\n };\n\n return {\n listPolicies,\n listPoliciesWithUnreadable,\n getPolicy,\n listRevisions,\n upsertPolicy,\n deletePolicy,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["z","z","metastoreObjectReadSchema","parseOrThrow","z","formatValidationIssues","isApiError","metastoreErrorMessage"],"sources":["../../../src/sdks/securityPolicy/vocabulary.ts","../../../src/sdks/securityPolicy/schemas.ts","../../../src/sdks/securityPolicy/readSchemas.ts","../../../src/sdks/securityPolicy/securityPolicySdk.ts"],"sourcesContent":["/**\n * The metastore's row- and column-level security vocabulary, schema version 1.2.0.\n *\n * - Each list is the one place a value is added; the types in `./types` derive from it.\n */\n\nexport const SECURITY_POLICY_TYPES = ['rls-policy', 'cls-policy'] as const;\n\nexport const POLICY_SQL_DIALECTS = ['snowflake', 'bigquery'] as const;\n\nexport const RLS_COMPARISON_OPS = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const;\n\nexport const RLS_LIST_OPS = ['in', 'not_in'] as const;\n\nexport const RLS_NULL_OPS = ['is_null', 'is_not_null'] as const;\n","import { z } from 'zod';\n\nimport type { ClsPolicyData, RlsCondition, RlsPolicyData } from './types';\nimport { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS } from './vocabulary';\n\n/** A `<bucket>.<table>` key; also the policy's metastore name. */\nconst POLICY_TABLE_PATTERN = /^[A-Za-z0-9_.-]+\\.[A-Za-z0-9_-]+$/;\n\n/** Columns are SQL identifiers that cannot be parameterised, so this pattern is the boundary. */\nconst POLICY_COLUMN_PATTERN = /^[A-Za-z0-9_]+$/;\n\n/** A reader selector `<idp>|<sub>`: the identity provider's issuer, a `|`, the user's `sub`. */\nconst POLICY_SUBJECT_PATTERN = /^[^|\\s]+\\|\\S.*$/;\n\n/**\n * Write validators for untrusted policy input, mirroring metastore schema 1.2.0.\n *\n * - Strict: an unknown key fails, as `additionalProperties: false` does in the metastore.\n * - The identifier patterns are the boundary: `table` and `column` reach SQL unparameterised.\n * - Stricter than the metastore on purpose: a `value` is a string, number, boolean or null, and\n * `values` holds the same; the metastore also lets an arbitrary JSON value through.\n * - The metastore stays the authority; this reports the first problem in words the model can act on.\n */\n\nconst column = z.string().regex(POLICY_COLUMN_PATTERN, 'column must match [A-Za-z0-9_]+');\n\nconst literal = z.union([z.string(), z.number(), z.boolean(), z.null()]);\n\nconst identityEmail = z.strictObject({ $identity: z.literal('email') });\nconst identityGroups = z.strictObject({ $identity: z.literal('groups') });\n\nconst rlsCondition: z.ZodType<RlsCondition> = z.lazy(() =>\n z.union([\n z.strictObject({ true: z.literal(true) }),\n z.strictObject({ false: z.literal(true) }),\n z.strictObject({ and: z.array(rlsCondition).min(2) }),\n z.strictObject({ or: z.array(rlsCondition).min(2) }),\n z.strictObject({\n column,\n op: z.enum(RLS_COMPARISON_OPS),\n value: z.union([literal, identityEmail]),\n }),\n z.strictObject({\n column,\n op: z.enum(RLS_LIST_OPS),\n values: z.union([z.array(literal).min(1), identityGroups]),\n }),\n z.strictObject({ column, op: z.enum(RLS_NULL_OPS) }),\n ]),\n);\n\n/** `[\"*\"]` is everyone and must be the only entry. */\nconst selectorList = (item: z.ZodType<string>) =>\n z\n .array(item)\n .min(1)\n .refine((list) => !list.includes('*') || list.length === 1, {\n message: '\"*\" must be the only entry',\n });\n\nconst subjects = selectorList(\n z.union([\n z.literal('*'),\n z\n .string()\n .max(1024)\n .regex(POLICY_SUBJECT_PATTERN, 'a subject is \"<idp>|<sub>\", never an email'),\n ]),\n);\nconst groups = selectorList(z.string().min(1));\n\n/** A rule selects readers by exactly one of `subjects` or `groups`, then carries `shape`. */\nconst rule = <Shape extends z.ZodRawShape>(shape: Shape) =>\n z.union([z.strictObject({ subjects, ...shape }), z.strictObject({ groups, ...shape })]);\n\nconst table = z.string().regex(POLICY_TABLE_PATTERN, 'table must be \"<bucket>.<table>\"');\nconst dialect = z.enum(POLICY_SQL_DIALECTS).optional();\n\nexport const rlsPolicySchema: z.ZodType<RlsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ condition: rlsCondition })).min(1),\n default: rlsCondition.optional(),\n});\n\nexport const clsPolicySchema: z.ZodType<ClsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ visible_columns: z.array(column).min(1) })).min(1),\n});\n","import { z } from 'zod';\n\nimport { metastoreObjectReadSchema } from '../../clients/metastore/metaObject';\n\nimport type { SecurityPolicyReadData } from './types';\nimport { POLICY_SQL_DIALECTS } from './vocabulary';\n\n/**\n * What a read of the metastore may hand back for a policy.\n *\n * - `looseObject`: fields the metastore adds still reach callers.\n * - An unknown `dialect` reads as absent; a missing `table` or `rules` drops the object.\n * - The envelope is the metastore's own, shared with every object family.\n */\n\nconst policyReadDataSchema: z.ZodType<SecurityPolicyReadData, unknown> = z.looseObject({\n table: z.string(),\n dialect: z.enum(POLICY_SQL_DIALECTS).optional().catch(undefined),\n rules: z.array(z.record(z.string(), z.unknown())),\n default: z.unknown().optional(),\n});\n\nexport const securityPolicyReadSchema = metastoreObjectReadSchema(policyReadDataSchema);\n","import { z } from 'zod';\n\nimport { metastoreErrorMessage } from '../../clients/metastore/errorMessage';\nimport { formatValidationIssues, parseOrThrow } from '../../errors';\nimport { isApiError } from '../../fetchClient';\n\nimport { securityPolicyReadSchema } from './readSchemas';\nimport type {\n MetastoreClient,\n SecurityPolicy,\n SecurityPolicyDataMap,\n SecurityPolicyType,\n} from './types';\n\nconst DEFAULT_BRANCH = 'main';\n\n/** The rule schema Kai writes; a policy created under another version keeps its own. */\nconst CURRENT_SCHEMA_VERSION = '1.2.0';\n\n/** A policy stored under an older rule schema: the metastore refuses current rules for it. */\nexport const isLegacySecurityPolicy = (\n meta: SecurityPolicy['meta'],\n): meta is SecurityPolicy['meta'] & { schemaVersion: string } =>\n meta.schemaVersion !== undefined && meta.schemaVersion !== CURRENT_SCHEMA_VERSION;\n\n// A list without `branch` returns every branch, and a create always writes `main`: a policy on\n// another branch is neither the one to replace nor one that stacks with it.\nconst onDefaultBranch = (policy: SecurityPolicy) =>\n policy.meta.branch === undefined || policy.meta.branch === DEFAULT_BRANCH;\n\n/**\n * Whether `projectId` owns the policy on `main`: a create for its table replaces it.\n *\n * - Others' policies on the table are never replaced; they stack with the project's own.\n */\nexport const isReplaceableSecurityPolicy = (policy: SecurityPolicy, projectId: number) =>\n policy.meta.projectId === projectId && onDefaultBranch(policy);\n\n/** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */\nexport class SecurityPolicyAmbiguousError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuids: string[];\n\n constructor({\n policyType,\n table,\n uuids,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuids: string[];\n }) {\n super(\n `The project has ${uuids.length} ${policyType} policies for table '${table}' ` +\n `(${uuids.join(', ')}); pass the uuid of the one to replace.`,\n );\n this.name = 'SecurityPolicyAmbiguousError';\n this.policyType = policyType;\n this.table = table;\n this.uuids = uuids;\n }\n}\n\n/**\n * Thrown by `deletePolicy` on a `409`: other objects still reference the policy, nothing was deleted.\n *\n * - The metastore does not name the referencing objects, so none is reported here.\n */\nexport class SecurityPolicyInUseError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n\n constructor({\n policyType,\n uuid,\n reason,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n reason?: string;\n }) {\n super(reason ?? `The ${policyType} policy '${uuid}' is still bound and was not deleted.`);\n this.name = 'SecurityPolicyInUseError';\n this.policyType = policyType;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when some policy of the type could not be read.\n *\n * - Whether that policy governs the table is unknown, and a second policy on it would AND with it.\n */\nexport class SecurityPolicyUnreadableError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly count: number;\n\n constructor({ policyType, count }: { policyType: SecurityPolicyType; count: number }) {\n super(\n `${count} ${policyType} polic${count === 1 ? 'y' : 'ies'} of the project could not be read, ` +\n `so it is unknown whether the table already has one; nothing was written.`,\n );\n this.name = 'SecurityPolicyUnreadableError';\n this.policyType = policyType;\n this.count = count;\n }\n}\n\n/** The caller named a policy by `uuid` that the project does not own for the table. */\nexport class SecurityPolicyNotFoundError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuid: string;\n\n constructor({\n policyType,\n table,\n uuid,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuid: string;\n }) {\n super(`The project owns no ${policyType} '${uuid}' for table '${table}'.`);\n this.name = 'SecurityPolicyNotFoundError';\n this.policyType = policyType;\n this.table = table;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when the policy to replace was written under an older schema.\n *\n * - The metastore validates a write against the schema version the object already has, so 1.2.0\n * `subjects` on a 1.0.0 or 1.1.0 policy (`principal`, `principals`) fail with a 422.\n * - Nothing was written. Delete the policy and create it again; a policy an app binds cannot be deleted.\n */\nexport class SecurityPolicyLegacyError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n readonly schemaVersion: string;\n\n constructor({\n policyType,\n uuid,\n schemaVersion,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n schemaVersion: string;\n }) {\n super(\n `The ${policyType} '${uuid}' is on schema ${schemaVersion}, not ${CURRENT_SCHEMA_VERSION}, ` +\n `and the metastore keeps a policy on the schema it was created with; nothing was written.`,\n );\n this.name = 'SecurityPolicyLegacyError';\n this.policyType = policyType;\n this.uuid = uuid;\n this.schemaVersion = schemaVersion;\n }\n}\n\ntype Options = {\n metastoreClient: MetastoreClient;\n /** The project the caller writes as; a policy it owns carries this in `meta.projectId`. */\n projectId: number;\n};\n\n/**\n * The policies in a metastore collection response.\n *\n * - A malformed element is dropped, logged without its payload and counted in `unreadable`.\n * - A response that is not a collection throws.\n */\nconst parsePolicies = (\n policyType: SecurityPolicyType,\n data: unknown,\n): { policies: SecurityPolicy[]; unreadable: number } => {\n const items = parseOrThrow(z.array(z.unknown()), data);\n\n const policies: SecurityPolicy[] = [];\n let unreadable = 0;\n for (const item of items) {\n const result = securityPolicyReadSchema.safeParse(item);\n if (result.success) {\n policies.push(result.data);\n continue;\n }\n\n unreadable += 1;\n // Never log the payload: it holds customer identities.\n console.warn(\n `securityPolicySdk: dropped a ${policyType} from the metastore response, it does not ` +\n `match its declared shape`,\n formatValidationIssues(result.error.issues),\n );\n }\n return { policies, unreadable };\n};\n\nexport const createSecurityPolicySdk = ({ metastoreClient, projectId }: Options) => {\n const isOwn = (policy: SecurityPolicy) => policy.meta.projectId === projectId;\n\n /**\n * Every policy of one type the caller can read.\n *\n * - A project admin reads only the policies the project owns. An organization admin also reads\n * organization-scope policies and ones shared into the project; `meta.projectId` tells them apart.\n * - A malformed element is dropped and logged; `listPoliciesWithUnreadable` also counts them.\n * - A response that is not a collection throws.\n */\n const listPoliciesWithUnreadable = async (\n policyType: SecurityPolicyType,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjects(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data);\n };\n\n const listPolicies = async (policyType: SecurityPolicyType, signal?: AbortSignal) =>\n (await listPoliciesWithUnreadable(policyType, signal)).policies;\n\n /**\n * One policy by UUID, from any project or scope the caller can read.\n *\n * - A policy that does not parse throws a `ValidationError` rather than reading as missing.\n * - `404`: no such policy, or the caller cannot see it.\n */\n const getPolicy = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObject(\n { objectType: policyType, UUID: policyUUID },\n signal,\n );\n return parseOrThrow(securityPolicyReadSchema, response.data);\n };\n\n /**\n * Every revision of one policy, newest first.\n *\n * - The metastore lists revisions per object type only, so this reads them all and keeps the policy's.\n * - A revision that does not parse is dropped and logged, as in `listPolicies`.\n */\n const listRevisions = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjectRevisions(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data)\n .policies.filter((revision) => revision.uuid === policyUUID)\n .sort((a, b) => (b.meta.revision ?? 0) - (a.meta.revision ?? 0));\n };\n\n /**\n * Creates the policy for its table, or replaces the one the project owns for it (a PUT).\n *\n * - Found by table on `main`; several owned ones throw `SecurityPolicyAmbiguousError`, `uuid` picks one.\n * - Others' policies are never replaced and come back in `otherPolicyUuids`; no scope is sent.\n * - Refused, nothing written: an unreadable policy of the type, or a legacy-schema one to replace.\n * - `existing`: a batch shares one listing, checks `unreadable` itself and must not repeat a table.\n */\n const upsertPolicy = async <T extends SecurityPolicyType>(\n policyType: T,\n data: SecurityPolicyDataMap[T],\n options: { existing?: SecurityPolicy[]; uuid?: string } = {},\n ): Promise<{ action: 'created' | 'updated'; uuid: string; otherPolicyUuids: string[] }> => {\n const { table } = data;\n let known = options.existing;\n if (known === undefined) {\n const listed = await listPoliciesWithUnreadable(policyType);\n if (listed.unreadable > 0) {\n throw new SecurityPolicyUnreadableError({ policyType, count: listed.unreadable });\n }\n known = listed.policies;\n }\n const onTable = known.filter(\n (policy) => policy.data.table === table && onDefaultBranch(policy),\n );\n const owned = onTable.filter((policy) => isReplaceableSecurityPolicy(policy, projectId));\n const otherPolicyUuids = onTable\n .filter((policy) => !isOwn(policy))\n .map((policy) => policy.uuid);\n\n const current =\n options.uuid === undefined ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);\n if (options.uuid !== undefined && current === undefined) {\n throw new SecurityPolicyNotFoundError({ policyType, table, uuid: options.uuid });\n }\n if (options.uuid === undefined && owned.length > 1) {\n throw new SecurityPolicyAmbiguousError({\n policyType,\n table,\n uuids: owned.map((policy) => policy.uuid),\n });\n }\n\n if (current) {\n if (isLegacySecurityPolicy(current.meta)) {\n throw new SecurityPolicyLegacyError({\n policyType,\n uuid: current.uuid,\n schemaVersion: current.meta.schemaVersion,\n });\n }\n await metastoreClient.repository.replaceMetaObject({\n objectType: policyType,\n UUID: current.uuid,\n data,\n name: current.meta.name ?? table,\n });\n return { action: 'updated', uuid: current.uuid, otherPolicyUuids };\n }\n\n const created = await metastoreClient.repository.createMetaObject({\n objectType: policyType,\n data,\n branch: DEFAULT_BRANCH,\n name: table,\n });\n return { action: 'created', uuid: created.data.id, otherPolicyUuids };\n };\n\n /**\n * - `SecurityPolicyInUseError` (`409`): other objects still reference the policy; nothing was deleted.\n * - `404`: no such policy, or it was already deleted.\n */\n const deletePolicy = async (policyType: SecurityPolicyType, policyUUID: string) => {\n try {\n await metastoreClient.repository.deleteMetaObject({\n objectType: policyType,\n UUID: policyUUID,\n });\n } catch (error) {\n if (!isApiError(error) || error.response.status !== 409) throw error;\n throw new SecurityPolicyInUseError({\n policyType,\n uuid: policyUUID,\n reason: metastoreErrorMessage(error.data),\n });\n }\n };\n\n return {\n listPolicies,\n listPoliciesWithUnreadable,\n getPolicy,\n listRevisions,\n upsertPolicy,\n deletePolicy,\n };\n};\n"],"mappings":"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"}
@@ -3,6 +3,16 @@ import { _ as RLS_COMPARISON_OPS, b as SECURITY_POLICY_TYPES, f as SecurityPolic
3
3
  import { z } from "zod";
4
4
  declare const rlsPolicySchema: z.ZodType<RlsPolicyData>;
5
5
  declare const clsPolicySchema: z.ZodType<ClsPolicyData>;
6
+ /** A policy stored under an older rule schema: the metastore refuses current rules for it. */
7
+ declare const isLegacySecurityPolicy: (meta: SecurityPolicy['meta']) => meta is SecurityPolicy['meta'] & {
8
+ schemaVersion: string;
9
+ };
10
+ /**
11
+ * Whether `projectId` owns the policy on `main`: a create for its table replaces it.
12
+ *
13
+ * - Others' policies on the table are never replaced; they stack with the project's own.
14
+ */
15
+ declare const isReplaceableSecurityPolicy: (policy: SecurityPolicy, projectId: number) => boolean;
6
16
  /** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */
7
17
  declare class SecurityPolicyAmbiguousError extends Error {
8
18
  readonly policyType: SecurityPolicyType;
@@ -96,5 +106,5 @@ declare const createSecurityPolicySdk: ({ metastoreClient, projectId }: Options)
96
106
  }>;
97
107
  deletePolicy: (policyType: SecurityPolicyType, policyUUID: string) => Promise<void>;
98
108
  };
99
- export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, rlsPolicySchema };
109
+ export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, isLegacySecurityPolicy, isReplaceableSecurityPolicy, rlsPolicySchema };
100
110
  //# sourceMappingURL=index.d.cts.map
@@ -3,6 +3,16 @@ import { _ as RLS_COMPARISON_OPS, b as SECURITY_POLICY_TYPES, f as SecurityPolic
3
3
  import { z } from "zod";
4
4
  declare const rlsPolicySchema: z.ZodType<RlsPolicyData>;
5
5
  declare const clsPolicySchema: z.ZodType<ClsPolicyData>;
6
+ /** A policy stored under an older rule schema: the metastore refuses current rules for it. */
7
+ declare const isLegacySecurityPolicy: (meta: SecurityPolicy['meta']) => meta is SecurityPolicy['meta'] & {
8
+ schemaVersion: string;
9
+ };
10
+ /**
11
+ * Whether `projectId` owns the policy on `main`: a create for its table replaces it.
12
+ *
13
+ * - Others' policies on the table are never replaced; they stack with the project's own.
14
+ */
15
+ declare const isReplaceableSecurityPolicy: (policy: SecurityPolicy, projectId: number) => boolean;
6
16
  /** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */
7
17
  declare class SecurityPolicyAmbiguousError extends Error {
8
18
  readonly policyType: SecurityPolicyType;
@@ -96,5 +106,5 @@ declare const createSecurityPolicySdk: ({ metastoreClient, projectId }: Options)
96
106
  }>;
97
107
  deletePolicy: (policyType: SecurityPolicyType, policyUUID: string) => Promise<void>;
98
108
  };
99
- export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, rlsPolicySchema };
109
+ export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, isLegacySecurityPolicy, isReplaceableSecurityPolicy, rlsPolicySchema };
100
110
  //# sourceMappingURL=index.d.ts.map
@@ -109,6 +109,15 @@ const securityPolicyReadSchema = metastoreObjectReadSchema(policyReadDataSchema)
109
109
  const DEFAULT_BRANCH = "main";
110
110
  /** The rule schema Kai writes; a policy created under another version keeps its own. */
111
111
  const CURRENT_SCHEMA_VERSION = "1.2.0";
112
+ /** A policy stored under an older rule schema: the metastore refuses current rules for it. */
113
+ const isLegacySecurityPolicy = (meta) => meta.schemaVersion !== void 0 && meta.schemaVersion !== CURRENT_SCHEMA_VERSION;
114
+ const onDefaultBranch = (policy) => policy.meta.branch === void 0 || policy.meta.branch === DEFAULT_BRANCH;
115
+ /**
116
+ * Whether `projectId` owns the policy on `main`: a create for its table replaces it.
117
+ *
118
+ * - Others' policies on the table are never replaced; they stack with the project's own.
119
+ */
120
+ const isReplaceableSecurityPolicy = (policy, projectId) => policy.meta.projectId === projectId && onDefaultBranch(policy);
112
121
  /** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */
113
122
  var SecurityPolicyAmbiguousError = class extends Error {
114
123
  policyType;
@@ -210,7 +219,6 @@ const parsePolicies = (policyType, data) => {
210
219
  };
211
220
  const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
212
221
  const isOwn = (policy) => policy.meta.projectId === projectId;
213
- const onDefaultBranch = (policy) => policy.meta.branch === void 0 || policy.meta.branch === DEFAULT_BRANCH;
214
222
  /**
215
223
  * Every policy of one type the caller can read.
216
224
  *
@@ -267,7 +275,7 @@ const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
267
275
  known = listed.policies;
268
276
  }
269
277
  const onTable = known.filter((policy) => policy.data.table === table && onDefaultBranch(policy));
270
- const owned = onTable.filter(isOwn);
278
+ const owned = onTable.filter((policy) => isReplaceableSecurityPolicy(policy, projectId));
271
279
  const otherPolicyUuids = onTable.filter((policy) => !isOwn(policy)).map((policy) => policy.uuid);
272
280
  const current = options.uuid === void 0 ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);
273
281
  if (options.uuid !== void 0 && current === void 0) throw new SecurityPolicyNotFoundError({
@@ -281,7 +289,7 @@ const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
281
289
  uuids: owned.map((policy) => policy.uuid)
282
290
  });
283
291
  if (current) {
284
- if (current.meta.schemaVersion !== void 0 && current.meta.schemaVersion !== CURRENT_SCHEMA_VERSION) throw new SecurityPolicyLegacyError({
292
+ if (isLegacySecurityPolicy(current.meta)) throw new SecurityPolicyLegacyError({
285
293
  policyType,
286
294
  uuid: current.uuid,
287
295
  schemaVersion: current.meta.schemaVersion
@@ -337,6 +345,6 @@ const createSecurityPolicySdk = ({ metastoreClient, projectId }) => {
337
345
  deletePolicy
338
346
  };
339
347
  };
340
- export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, rlsPolicySchema };
348
+ export { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS, SECURITY_POLICY_TYPES, SecurityPolicyAmbiguousError, SecurityPolicyInUseError, SecurityPolicyLegacyError, SecurityPolicyNotFoundError, SecurityPolicyUnreadableError, clsPolicySchema, createSecurityPolicySdk, isLegacySecurityPolicy, isReplaceableSecurityPolicy, rlsPolicySchema };
341
349
 
342
350
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/sdks/securityPolicy/vocabulary.ts","../../../src/sdks/securityPolicy/schemas.ts","../../../src/sdks/securityPolicy/readSchemas.ts","../../../src/sdks/securityPolicy/securityPolicySdk.ts"],"sourcesContent":["/**\n * The metastore's row- and column-level security vocabulary, schema version 1.2.0.\n *\n * - Each list is the one place a value is added; the types in `./types` derive from it.\n */\n\nexport const SECURITY_POLICY_TYPES = ['rls-policy', 'cls-policy'] as const;\n\nexport const POLICY_SQL_DIALECTS = ['snowflake', 'bigquery'] as const;\n\nexport const RLS_COMPARISON_OPS = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const;\n\nexport const RLS_LIST_OPS = ['in', 'not_in'] as const;\n\nexport const RLS_NULL_OPS = ['is_null', 'is_not_null'] as const;\n","import { z } from 'zod';\n\nimport type { ClsPolicyData, RlsCondition, RlsPolicyData } from './types';\nimport { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS } from './vocabulary';\n\n/** A `<bucket>.<table>` key; also the policy's metastore name. */\nconst POLICY_TABLE_PATTERN = /^[A-Za-z0-9_.-]+\\.[A-Za-z0-9_-]+$/;\n\n/** Columns are SQL identifiers that cannot be parameterised, so this pattern is the boundary. */\nconst POLICY_COLUMN_PATTERN = /^[A-Za-z0-9_]+$/;\n\n/** A reader selector `<idp>|<sub>`: the identity provider's issuer, a `|`, the user's `sub`. */\nconst POLICY_SUBJECT_PATTERN = /^[^|\\s]+\\|\\S.*$/;\n\n/**\n * Write validators for untrusted policy input, mirroring metastore schema 1.2.0.\n *\n * - Strict: an unknown key fails, as `additionalProperties: false` does in the metastore.\n * - The identifier patterns are the boundary: `table` and `column` reach SQL unparameterised.\n * - Stricter than the metastore on purpose: a `value` is a string, number, boolean or null, and\n * `values` holds the same; the metastore also lets an arbitrary JSON value through.\n * - The metastore stays the authority; this reports the first problem in words the model can act on.\n */\n\nconst column = z.string().regex(POLICY_COLUMN_PATTERN, 'column must match [A-Za-z0-9_]+');\n\nconst literal = z.union([z.string(), z.number(), z.boolean(), z.null()]);\n\nconst identityEmail = z.strictObject({ $identity: z.literal('email') });\nconst identityGroups = z.strictObject({ $identity: z.literal('groups') });\n\nconst rlsCondition: z.ZodType<RlsCondition> = z.lazy(() =>\n z.union([\n z.strictObject({ true: z.literal(true) }),\n z.strictObject({ false: z.literal(true) }),\n z.strictObject({ and: z.array(rlsCondition).min(2) }),\n z.strictObject({ or: z.array(rlsCondition).min(2) }),\n z.strictObject({\n column,\n op: z.enum(RLS_COMPARISON_OPS),\n value: z.union([literal, identityEmail]),\n }),\n z.strictObject({\n column,\n op: z.enum(RLS_LIST_OPS),\n values: z.union([z.array(literal).min(1), identityGroups]),\n }),\n z.strictObject({ column, op: z.enum(RLS_NULL_OPS) }),\n ]),\n);\n\n/** `[\"*\"]` is everyone and must be the only entry. */\nconst selectorList = (item: z.ZodType<string>) =>\n z\n .array(item)\n .min(1)\n .refine((list) => !list.includes('*') || list.length === 1, {\n message: '\"*\" must be the only entry',\n });\n\nconst subjects = selectorList(\n z.union([\n z.literal('*'),\n z\n .string()\n .max(1024)\n .regex(POLICY_SUBJECT_PATTERN, 'a subject is \"<idp>|<sub>\", never an email'),\n ]),\n);\nconst groups = selectorList(z.string().min(1));\n\n/** A rule selects readers by exactly one of `subjects` or `groups`, then carries `shape`. */\nconst rule = <Shape extends z.ZodRawShape>(shape: Shape) =>\n z.union([z.strictObject({ subjects, ...shape }), z.strictObject({ groups, ...shape })]);\n\nconst table = z.string().regex(POLICY_TABLE_PATTERN, 'table must be \"<bucket>.<table>\"');\nconst dialect = z.enum(POLICY_SQL_DIALECTS).optional();\n\nexport const rlsPolicySchema: z.ZodType<RlsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ condition: rlsCondition })).min(1),\n default: rlsCondition.optional(),\n});\n\nexport const clsPolicySchema: z.ZodType<ClsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ visible_columns: z.array(column).min(1) })).min(1),\n});\n","import { z } from 'zod';\n\nimport { metastoreObjectReadSchema } from '../../clients/metastore/metaObject';\n\nimport type { SecurityPolicyReadData } from './types';\nimport { POLICY_SQL_DIALECTS } from './vocabulary';\n\n/**\n * What a read of the metastore may hand back for a policy.\n *\n * - `looseObject`: fields the metastore adds still reach callers.\n * - An unknown `dialect` reads as absent; a missing `table` or `rules` drops the object.\n * - The envelope is the metastore's own, shared with every object family.\n */\n\nconst policyReadDataSchema: z.ZodType<SecurityPolicyReadData, unknown> = z.looseObject({\n table: z.string(),\n dialect: z.enum(POLICY_SQL_DIALECTS).optional().catch(undefined),\n rules: z.array(z.record(z.string(), z.unknown())),\n default: z.unknown().optional(),\n});\n\nexport const securityPolicyReadSchema = metastoreObjectReadSchema(policyReadDataSchema);\n","import { z } from 'zod';\n\nimport { metastoreErrorMessage } from '../../clients/metastore/errorMessage';\nimport { formatValidationIssues, parseOrThrow } from '../../errors';\nimport { isApiError } from '../../fetchClient';\n\nimport { securityPolicyReadSchema } from './readSchemas';\nimport type {\n MetastoreClient,\n SecurityPolicy,\n SecurityPolicyDataMap,\n SecurityPolicyType,\n} from './types';\n\nconst DEFAULT_BRANCH = 'main';\n\n/** The rule schema Kai writes; a policy created under another version keeps its own. */\nconst CURRENT_SCHEMA_VERSION = '1.2.0';\n\n/** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */\nexport class SecurityPolicyAmbiguousError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuids: string[];\n\n constructor({\n policyType,\n table,\n uuids,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuids: string[];\n }) {\n super(\n `The project has ${uuids.length} ${policyType} policies for table '${table}' ` +\n `(${uuids.join(', ')}); pass the uuid of the one to replace.`,\n );\n this.name = 'SecurityPolicyAmbiguousError';\n this.policyType = policyType;\n this.table = table;\n this.uuids = uuids;\n }\n}\n\n/**\n * Thrown by `deletePolicy` on a `409`: other objects still reference the policy, nothing was deleted.\n *\n * - The metastore does not name the referencing objects, so none is reported here.\n */\nexport class SecurityPolicyInUseError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n\n constructor({\n policyType,\n uuid,\n reason,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n reason?: string;\n }) {\n super(reason ?? `The ${policyType} policy '${uuid}' is still bound and was not deleted.`);\n this.name = 'SecurityPolicyInUseError';\n this.policyType = policyType;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when some policy of the type could not be read.\n *\n * - Whether that policy governs the table is unknown, and a second policy on it would AND with it.\n */\nexport class SecurityPolicyUnreadableError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly count: number;\n\n constructor({ policyType, count }: { policyType: SecurityPolicyType; count: number }) {\n super(\n `${count} ${policyType} polic${count === 1 ? 'y' : 'ies'} of the project could not be read, ` +\n `so it is unknown whether the table already has one; nothing was written.`,\n );\n this.name = 'SecurityPolicyUnreadableError';\n this.policyType = policyType;\n this.count = count;\n }\n}\n\n/** The caller named a policy by `uuid` that the project does not own for the table. */\nexport class SecurityPolicyNotFoundError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuid: string;\n\n constructor({\n policyType,\n table,\n uuid,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuid: string;\n }) {\n super(`The project owns no ${policyType} '${uuid}' for table '${table}'.`);\n this.name = 'SecurityPolicyNotFoundError';\n this.policyType = policyType;\n this.table = table;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when the policy to replace was written under an older schema.\n *\n * - The metastore validates a write against the schema version the object already has, so 1.2.0\n * `subjects` on a 1.0.0 or 1.1.0 policy (`principal`, `principals`) fail with a 422.\n * - Nothing was written. Delete the policy and create it again; a policy an app binds cannot be deleted.\n */\nexport class SecurityPolicyLegacyError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n readonly schemaVersion: string;\n\n constructor({\n policyType,\n uuid,\n schemaVersion,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n schemaVersion: string;\n }) {\n super(\n `The ${policyType} '${uuid}' is on schema ${schemaVersion}, not ${CURRENT_SCHEMA_VERSION}, ` +\n `and the metastore keeps a policy on the schema it was created with; nothing was written.`,\n );\n this.name = 'SecurityPolicyLegacyError';\n this.policyType = policyType;\n this.uuid = uuid;\n this.schemaVersion = schemaVersion;\n }\n}\n\ntype Options = {\n metastoreClient: MetastoreClient;\n /** The project the caller writes as; a policy it owns carries this in `meta.projectId`. */\n projectId: number;\n};\n\n/**\n * The policies in a metastore collection response.\n *\n * - A malformed element is dropped, logged without its payload and counted in `unreadable`.\n * - A response that is not a collection throws.\n */\nconst parsePolicies = (\n policyType: SecurityPolicyType,\n data: unknown,\n): { policies: SecurityPolicy[]; unreadable: number } => {\n const items = parseOrThrow(z.array(z.unknown()), data);\n\n const policies: SecurityPolicy[] = [];\n let unreadable = 0;\n for (const item of items) {\n const result = securityPolicyReadSchema.safeParse(item);\n if (result.success) {\n policies.push(result.data);\n continue;\n }\n\n unreadable += 1;\n // Never log the payload: it holds customer identities.\n console.warn(\n `securityPolicySdk: dropped a ${policyType} from the metastore response, it does not ` +\n `match its declared shape`,\n formatValidationIssues(result.error.issues),\n );\n }\n return { policies, unreadable };\n};\n\nexport const createSecurityPolicySdk = ({ metastoreClient, projectId }: Options) => {\n const isOwn = (policy: SecurityPolicy) => policy.meta.projectId === projectId;\n\n // A list without `branch` returns every branch, and a create always writes `main`: a policy on\n // another branch is neither the one to replace nor one that stacks with it.\n const onDefaultBranch = (policy: SecurityPolicy) =>\n policy.meta.branch === undefined || policy.meta.branch === DEFAULT_BRANCH;\n\n /**\n * Every policy of one type the caller can read.\n *\n * - A project admin reads only the policies the project owns. An organization admin also reads\n * organization-scope policies and ones shared into the project; `meta.projectId` tells them apart.\n * - A malformed element is dropped and logged; `listPoliciesWithUnreadable` also counts them.\n * - A response that is not a collection throws.\n */\n const listPoliciesWithUnreadable = async (\n policyType: SecurityPolicyType,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjects(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data);\n };\n\n const listPolicies = async (policyType: SecurityPolicyType, signal?: AbortSignal) =>\n (await listPoliciesWithUnreadable(policyType, signal)).policies;\n\n /**\n * One policy by UUID, from any project or scope the caller can read.\n *\n * - A policy that does not parse throws a `ValidationError` rather than reading as missing.\n * - `404`: no such policy, or the caller cannot see it.\n */\n const getPolicy = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObject(\n { objectType: policyType, UUID: policyUUID },\n signal,\n );\n return parseOrThrow(securityPolicyReadSchema, response.data);\n };\n\n /**\n * Every revision of one policy, newest first.\n *\n * - The metastore lists revisions per object type only, so this reads them all and keeps the policy's.\n * - A revision that does not parse is dropped and logged, as in `listPolicies`.\n */\n const listRevisions = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjectRevisions(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data)\n .policies.filter((revision) => revision.uuid === policyUUID)\n .sort((a, b) => (b.meta.revision ?? 0) - (a.meta.revision ?? 0));\n };\n\n /**\n * Creates the policy for its table, or replaces the one the project owns for it (a PUT).\n *\n * - Found by table on `main`; several owned ones throw `SecurityPolicyAmbiguousError`, `uuid` picks one.\n * - Others' policies are never replaced and come back in `otherPolicyUuids`; no scope is sent.\n * - Refused, nothing written: an unreadable policy of the type, or a legacy-schema one to replace.\n * - `existing`: a batch shares one listing, checks `unreadable` itself and must not repeat a table.\n */\n const upsertPolicy = async <T extends SecurityPolicyType>(\n policyType: T,\n data: SecurityPolicyDataMap[T],\n options: { existing?: SecurityPolicy[]; uuid?: string } = {},\n ): Promise<{ action: 'created' | 'updated'; uuid: string; otherPolicyUuids: string[] }> => {\n const { table } = data;\n let known = options.existing;\n if (known === undefined) {\n const listed = await listPoliciesWithUnreadable(policyType);\n if (listed.unreadable > 0) {\n throw new SecurityPolicyUnreadableError({ policyType, count: listed.unreadable });\n }\n known = listed.policies;\n }\n const onTable = known.filter(\n (policy) => policy.data.table === table && onDefaultBranch(policy),\n );\n const owned = onTable.filter(isOwn);\n const otherPolicyUuids = onTable\n .filter((policy) => !isOwn(policy))\n .map((policy) => policy.uuid);\n\n const current =\n options.uuid === undefined ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);\n if (options.uuid !== undefined && current === undefined) {\n throw new SecurityPolicyNotFoundError({ policyType, table, uuid: options.uuid });\n }\n if (options.uuid === undefined && owned.length > 1) {\n throw new SecurityPolicyAmbiguousError({\n policyType,\n table,\n uuids: owned.map((policy) => policy.uuid),\n });\n }\n\n if (current) {\n if (\n current.meta.schemaVersion !== undefined &&\n current.meta.schemaVersion !== CURRENT_SCHEMA_VERSION\n ) {\n throw new SecurityPolicyLegacyError({\n policyType,\n uuid: current.uuid,\n schemaVersion: current.meta.schemaVersion,\n });\n }\n await metastoreClient.repository.replaceMetaObject({\n objectType: policyType,\n UUID: current.uuid,\n data,\n name: current.meta.name ?? table,\n });\n return { action: 'updated', uuid: current.uuid, otherPolicyUuids };\n }\n\n const created = await metastoreClient.repository.createMetaObject({\n objectType: policyType,\n data,\n branch: DEFAULT_BRANCH,\n name: table,\n });\n return { action: 'created', uuid: created.data.id, otherPolicyUuids };\n };\n\n /**\n * - `SecurityPolicyInUseError` (`409`): other objects still reference the policy; nothing was deleted.\n * - `404`: no such policy, or it was already deleted.\n */\n const deletePolicy = async (policyType: SecurityPolicyType, policyUUID: string) => {\n try {\n await metastoreClient.repository.deleteMetaObject({\n objectType: policyType,\n UUID: policyUUID,\n });\n } catch (error) {\n if (!isApiError(error) || error.response.status !== 409) throw error;\n throw new SecurityPolicyInUseError({\n policyType,\n uuid: policyUUID,\n reason: metastoreErrorMessage(error.data),\n });\n }\n };\n\n return {\n listPolicies,\n listPoliciesWithUnreadable,\n getPolicy,\n listRevisions,\n upsertPolicy,\n deletePolicy,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/sdks/securityPolicy/vocabulary.ts","../../../src/sdks/securityPolicy/schemas.ts","../../../src/sdks/securityPolicy/readSchemas.ts","../../../src/sdks/securityPolicy/securityPolicySdk.ts"],"sourcesContent":["/**\n * The metastore's row- and column-level security vocabulary, schema version 1.2.0.\n *\n * - Each list is the one place a value is added; the types in `./types` derive from it.\n */\n\nexport const SECURITY_POLICY_TYPES = ['rls-policy', 'cls-policy'] as const;\n\nexport const POLICY_SQL_DIALECTS = ['snowflake', 'bigquery'] as const;\n\nexport const RLS_COMPARISON_OPS = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const;\n\nexport const RLS_LIST_OPS = ['in', 'not_in'] as const;\n\nexport const RLS_NULL_OPS = ['is_null', 'is_not_null'] as const;\n","import { z } from 'zod';\n\nimport type { ClsPolicyData, RlsCondition, RlsPolicyData } from './types';\nimport { POLICY_SQL_DIALECTS, RLS_COMPARISON_OPS, RLS_LIST_OPS, RLS_NULL_OPS } from './vocabulary';\n\n/** A `<bucket>.<table>` key; also the policy's metastore name. */\nconst POLICY_TABLE_PATTERN = /^[A-Za-z0-9_.-]+\\.[A-Za-z0-9_-]+$/;\n\n/** Columns are SQL identifiers that cannot be parameterised, so this pattern is the boundary. */\nconst POLICY_COLUMN_PATTERN = /^[A-Za-z0-9_]+$/;\n\n/** A reader selector `<idp>|<sub>`: the identity provider's issuer, a `|`, the user's `sub`. */\nconst POLICY_SUBJECT_PATTERN = /^[^|\\s]+\\|\\S.*$/;\n\n/**\n * Write validators for untrusted policy input, mirroring metastore schema 1.2.0.\n *\n * - Strict: an unknown key fails, as `additionalProperties: false` does in the metastore.\n * - The identifier patterns are the boundary: `table` and `column` reach SQL unparameterised.\n * - Stricter than the metastore on purpose: a `value` is a string, number, boolean or null, and\n * `values` holds the same; the metastore also lets an arbitrary JSON value through.\n * - The metastore stays the authority; this reports the first problem in words the model can act on.\n */\n\nconst column = z.string().regex(POLICY_COLUMN_PATTERN, 'column must match [A-Za-z0-9_]+');\n\nconst literal = z.union([z.string(), z.number(), z.boolean(), z.null()]);\n\nconst identityEmail = z.strictObject({ $identity: z.literal('email') });\nconst identityGroups = z.strictObject({ $identity: z.literal('groups') });\n\nconst rlsCondition: z.ZodType<RlsCondition> = z.lazy(() =>\n z.union([\n z.strictObject({ true: z.literal(true) }),\n z.strictObject({ false: z.literal(true) }),\n z.strictObject({ and: z.array(rlsCondition).min(2) }),\n z.strictObject({ or: z.array(rlsCondition).min(2) }),\n z.strictObject({\n column,\n op: z.enum(RLS_COMPARISON_OPS),\n value: z.union([literal, identityEmail]),\n }),\n z.strictObject({\n column,\n op: z.enum(RLS_LIST_OPS),\n values: z.union([z.array(literal).min(1), identityGroups]),\n }),\n z.strictObject({ column, op: z.enum(RLS_NULL_OPS) }),\n ]),\n);\n\n/** `[\"*\"]` is everyone and must be the only entry. */\nconst selectorList = (item: z.ZodType<string>) =>\n z\n .array(item)\n .min(1)\n .refine((list) => !list.includes('*') || list.length === 1, {\n message: '\"*\" must be the only entry',\n });\n\nconst subjects = selectorList(\n z.union([\n z.literal('*'),\n z\n .string()\n .max(1024)\n .regex(POLICY_SUBJECT_PATTERN, 'a subject is \"<idp>|<sub>\", never an email'),\n ]),\n);\nconst groups = selectorList(z.string().min(1));\n\n/** A rule selects readers by exactly one of `subjects` or `groups`, then carries `shape`. */\nconst rule = <Shape extends z.ZodRawShape>(shape: Shape) =>\n z.union([z.strictObject({ subjects, ...shape }), z.strictObject({ groups, ...shape })]);\n\nconst table = z.string().regex(POLICY_TABLE_PATTERN, 'table must be \"<bucket>.<table>\"');\nconst dialect = z.enum(POLICY_SQL_DIALECTS).optional();\n\nexport const rlsPolicySchema: z.ZodType<RlsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ condition: rlsCondition })).min(1),\n default: rlsCondition.optional(),\n});\n\nexport const clsPolicySchema: z.ZodType<ClsPolicyData> = z.strictObject({\n table,\n dialect,\n rules: z.array(rule({ visible_columns: z.array(column).min(1) })).min(1),\n});\n","import { z } from 'zod';\n\nimport { metastoreObjectReadSchema } from '../../clients/metastore/metaObject';\n\nimport type { SecurityPolicyReadData } from './types';\nimport { POLICY_SQL_DIALECTS } from './vocabulary';\n\n/**\n * What a read of the metastore may hand back for a policy.\n *\n * - `looseObject`: fields the metastore adds still reach callers.\n * - An unknown `dialect` reads as absent; a missing `table` or `rules` drops the object.\n * - The envelope is the metastore's own, shared with every object family.\n */\n\nconst policyReadDataSchema: z.ZodType<SecurityPolicyReadData, unknown> = z.looseObject({\n table: z.string(),\n dialect: z.enum(POLICY_SQL_DIALECTS).optional().catch(undefined),\n rules: z.array(z.record(z.string(), z.unknown())),\n default: z.unknown().optional(),\n});\n\nexport const securityPolicyReadSchema = metastoreObjectReadSchema(policyReadDataSchema);\n","import { z } from 'zod';\n\nimport { metastoreErrorMessage } from '../../clients/metastore/errorMessage';\nimport { formatValidationIssues, parseOrThrow } from '../../errors';\nimport { isApiError } from '../../fetchClient';\n\nimport { securityPolicyReadSchema } from './readSchemas';\nimport type {\n MetastoreClient,\n SecurityPolicy,\n SecurityPolicyDataMap,\n SecurityPolicyType,\n} from './types';\n\nconst DEFAULT_BRANCH = 'main';\n\n/** The rule schema Kai writes; a policy created under another version keeps its own. */\nconst CURRENT_SCHEMA_VERSION = '1.2.0';\n\n/** A policy stored under an older rule schema: the metastore refuses current rules for it. */\nexport const isLegacySecurityPolicy = (\n meta: SecurityPolicy['meta'],\n): meta is SecurityPolicy['meta'] & { schemaVersion: string } =>\n meta.schemaVersion !== undefined && meta.schemaVersion !== CURRENT_SCHEMA_VERSION;\n\n// A list without `branch` returns every branch, and a create always writes `main`: a policy on\n// another branch is neither the one to replace nor one that stacks with it.\nconst onDefaultBranch = (policy: SecurityPolicy) =>\n policy.meta.branch === undefined || policy.meta.branch === DEFAULT_BRANCH;\n\n/**\n * Whether `projectId` owns the policy on `main`: a create for its table replaces it.\n *\n * - Others' policies on the table are never replaced; they stack with the project's own.\n */\nexport const isReplaceableSecurityPolicy = (policy: SecurityPolicy, projectId: number) =>\n policy.meta.projectId === projectId && onDefaultBranch(policy);\n\n/** The project owns more than one policy for the table, so which to replace is not for the SDK to guess. */\nexport class SecurityPolicyAmbiguousError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuids: string[];\n\n constructor({\n policyType,\n table,\n uuids,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuids: string[];\n }) {\n super(\n `The project has ${uuids.length} ${policyType} policies for table '${table}' ` +\n `(${uuids.join(', ')}); pass the uuid of the one to replace.`,\n );\n this.name = 'SecurityPolicyAmbiguousError';\n this.policyType = policyType;\n this.table = table;\n this.uuids = uuids;\n }\n}\n\n/**\n * Thrown by `deletePolicy` on a `409`: other objects still reference the policy, nothing was deleted.\n *\n * - The metastore does not name the referencing objects, so none is reported here.\n */\nexport class SecurityPolicyInUseError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n\n constructor({\n policyType,\n uuid,\n reason,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n reason?: string;\n }) {\n super(reason ?? `The ${policyType} policy '${uuid}' is still bound and was not deleted.`);\n this.name = 'SecurityPolicyInUseError';\n this.policyType = policyType;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when some policy of the type could not be read.\n *\n * - Whether that policy governs the table is unknown, and a second policy on it would AND with it.\n */\nexport class SecurityPolicyUnreadableError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly count: number;\n\n constructor({ policyType, count }: { policyType: SecurityPolicyType; count: number }) {\n super(\n `${count} ${policyType} polic${count === 1 ? 'y' : 'ies'} of the project could not be read, ` +\n `so it is unknown whether the table already has one; nothing was written.`,\n );\n this.name = 'SecurityPolicyUnreadableError';\n this.policyType = policyType;\n this.count = count;\n }\n}\n\n/** The caller named a policy by `uuid` that the project does not own for the table. */\nexport class SecurityPolicyNotFoundError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly table: string;\n readonly uuid: string;\n\n constructor({\n policyType,\n table,\n uuid,\n }: {\n policyType: SecurityPolicyType;\n table: string;\n uuid: string;\n }) {\n super(`The project owns no ${policyType} '${uuid}' for table '${table}'.`);\n this.name = 'SecurityPolicyNotFoundError';\n this.policyType = policyType;\n this.table = table;\n this.uuid = uuid;\n }\n}\n\n/**\n * Thrown by `upsertPolicy` when the policy to replace was written under an older schema.\n *\n * - The metastore validates a write against the schema version the object already has, so 1.2.0\n * `subjects` on a 1.0.0 or 1.1.0 policy (`principal`, `principals`) fail with a 422.\n * - Nothing was written. Delete the policy and create it again; a policy an app binds cannot be deleted.\n */\nexport class SecurityPolicyLegacyError extends Error {\n readonly policyType: SecurityPolicyType;\n readonly uuid: string;\n readonly schemaVersion: string;\n\n constructor({\n policyType,\n uuid,\n schemaVersion,\n }: {\n policyType: SecurityPolicyType;\n uuid: string;\n schemaVersion: string;\n }) {\n super(\n `The ${policyType} '${uuid}' is on schema ${schemaVersion}, not ${CURRENT_SCHEMA_VERSION}, ` +\n `and the metastore keeps a policy on the schema it was created with; nothing was written.`,\n );\n this.name = 'SecurityPolicyLegacyError';\n this.policyType = policyType;\n this.uuid = uuid;\n this.schemaVersion = schemaVersion;\n }\n}\n\ntype Options = {\n metastoreClient: MetastoreClient;\n /** The project the caller writes as; a policy it owns carries this in `meta.projectId`. */\n projectId: number;\n};\n\n/**\n * The policies in a metastore collection response.\n *\n * - A malformed element is dropped, logged without its payload and counted in `unreadable`.\n * - A response that is not a collection throws.\n */\nconst parsePolicies = (\n policyType: SecurityPolicyType,\n data: unknown,\n): { policies: SecurityPolicy[]; unreadable: number } => {\n const items = parseOrThrow(z.array(z.unknown()), data);\n\n const policies: SecurityPolicy[] = [];\n let unreadable = 0;\n for (const item of items) {\n const result = securityPolicyReadSchema.safeParse(item);\n if (result.success) {\n policies.push(result.data);\n continue;\n }\n\n unreadable += 1;\n // Never log the payload: it holds customer identities.\n console.warn(\n `securityPolicySdk: dropped a ${policyType} from the metastore response, it does not ` +\n `match its declared shape`,\n formatValidationIssues(result.error.issues),\n );\n }\n return { policies, unreadable };\n};\n\nexport const createSecurityPolicySdk = ({ metastoreClient, projectId }: Options) => {\n const isOwn = (policy: SecurityPolicy) => policy.meta.projectId === projectId;\n\n /**\n * Every policy of one type the caller can read.\n *\n * - A project admin reads only the policies the project owns. An organization admin also reads\n * organization-scope policies and ones shared into the project; `meta.projectId` tells them apart.\n * - A malformed element is dropped and logged; `listPoliciesWithUnreadable` also counts them.\n * - A response that is not a collection throws.\n */\n const listPoliciesWithUnreadable = async (\n policyType: SecurityPolicyType,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjects(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data);\n };\n\n const listPolicies = async (policyType: SecurityPolicyType, signal?: AbortSignal) =>\n (await listPoliciesWithUnreadable(policyType, signal)).policies;\n\n /**\n * One policy by UUID, from any project or scope the caller can read.\n *\n * - A policy that does not parse throws a `ValidationError` rather than reading as missing.\n * - `404`: no such policy, or the caller cannot see it.\n */\n const getPolicy = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObject(\n { objectType: policyType, UUID: policyUUID },\n signal,\n );\n return parseOrThrow(securityPolicyReadSchema, response.data);\n };\n\n /**\n * Every revision of one policy, newest first.\n *\n * - The metastore lists revisions per object type only, so this reads them all and keeps the policy's.\n * - A revision that does not parse is dropped and logged, as in `listPolicies`.\n */\n const listRevisions = async (\n policyType: SecurityPolicyType,\n policyUUID: string,\n signal?: AbortSignal,\n ) => {\n const response = await metastoreClient.repository.getMetaObjectRevisions(\n { objectType: policyType },\n signal,\n );\n return parsePolicies(policyType, response.data)\n .policies.filter((revision) => revision.uuid === policyUUID)\n .sort((a, b) => (b.meta.revision ?? 0) - (a.meta.revision ?? 0));\n };\n\n /**\n * Creates the policy for its table, or replaces the one the project owns for it (a PUT).\n *\n * - Found by table on `main`; several owned ones throw `SecurityPolicyAmbiguousError`, `uuid` picks one.\n * - Others' policies are never replaced and come back in `otherPolicyUuids`; no scope is sent.\n * - Refused, nothing written: an unreadable policy of the type, or a legacy-schema one to replace.\n * - `existing`: a batch shares one listing, checks `unreadable` itself and must not repeat a table.\n */\n const upsertPolicy = async <T extends SecurityPolicyType>(\n policyType: T,\n data: SecurityPolicyDataMap[T],\n options: { existing?: SecurityPolicy[]; uuid?: string } = {},\n ): Promise<{ action: 'created' | 'updated'; uuid: string; otherPolicyUuids: string[] }> => {\n const { table } = data;\n let known = options.existing;\n if (known === undefined) {\n const listed = await listPoliciesWithUnreadable(policyType);\n if (listed.unreadable > 0) {\n throw new SecurityPolicyUnreadableError({ policyType, count: listed.unreadable });\n }\n known = listed.policies;\n }\n const onTable = known.filter(\n (policy) => policy.data.table === table && onDefaultBranch(policy),\n );\n const owned = onTable.filter((policy) => isReplaceableSecurityPolicy(policy, projectId));\n const otherPolicyUuids = onTable\n .filter((policy) => !isOwn(policy))\n .map((policy) => policy.uuid);\n\n const current =\n options.uuid === undefined ? owned[0] : owned.find((policy) => policy.uuid === options.uuid);\n if (options.uuid !== undefined && current === undefined) {\n throw new SecurityPolicyNotFoundError({ policyType, table, uuid: options.uuid });\n }\n if (options.uuid === undefined && owned.length > 1) {\n throw new SecurityPolicyAmbiguousError({\n policyType,\n table,\n uuids: owned.map((policy) => policy.uuid),\n });\n }\n\n if (current) {\n if (isLegacySecurityPolicy(current.meta)) {\n throw new SecurityPolicyLegacyError({\n policyType,\n uuid: current.uuid,\n schemaVersion: current.meta.schemaVersion,\n });\n }\n await metastoreClient.repository.replaceMetaObject({\n objectType: policyType,\n UUID: current.uuid,\n data,\n name: current.meta.name ?? table,\n });\n return { action: 'updated', uuid: current.uuid, otherPolicyUuids };\n }\n\n const created = await metastoreClient.repository.createMetaObject({\n objectType: policyType,\n data,\n branch: DEFAULT_BRANCH,\n name: table,\n });\n return { action: 'created', uuid: created.data.id, otherPolicyUuids };\n };\n\n /**\n * - `SecurityPolicyInUseError` (`409`): other objects still reference the policy; nothing was deleted.\n * - `404`: no such policy, or it was already deleted.\n */\n const deletePolicy = async (policyType: SecurityPolicyType, policyUUID: string) => {\n try {\n await metastoreClient.repository.deleteMetaObject({\n objectType: policyType,\n UUID: policyUUID,\n });\n } catch (error) {\n if (!isApiError(error) || error.response.status !== 409) throw error;\n throw new SecurityPolicyInUseError({\n policyType,\n uuid: policyUUID,\n reason: metastoreErrorMessage(error.data),\n });\n }\n };\n\n return {\n listPolicies,\n listPoliciesWithUnreadable,\n getPolicy,\n listRevisions,\n upsertPolicy,\n deletePolicy,\n };\n};\n"],"mappings":"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"}
@@ -16,18 +16,9 @@ const vaultRef = {
16
16
  decode: (s) => s.match(VAULT_REF_RE)?.[1] ?? null,
17
17
  isMatch: (s) => VAULT_REF_RE.test(s)
18
18
  };
19
- const partitionByOauth = (variables) => variables.reduce((acc, variable) => {
20
- if (isVariableOauth(variable)) return {
21
- ...acc,
22
- oauth: [...acc.oauth, variable]
23
- };
24
- return {
25
- ...acc,
26
- regular: [...acc.regular, variable]
27
- };
28
- }, {
29
- oauth: [],
30
- regular: []
19
+ const partitionByOauth = (variables) => ({
20
+ oauth: variables.filter((variable) => isVariableOauth(variable)),
21
+ regular: variables.filter((variable) => !isVariableOauth(variable))
31
22
  });
32
23
  // src/sdks/vault/vaultSdk.ts
33
24
  const resolveBranchType = (variable, defaultBranchId) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["concurrent"],"sources":["../../../src/sdks/vault/helpers.ts","../../../src/sdks/vault/vaultSdk.ts"],"sourcesContent":["import type { AnyVariable, CreateVariableBody } from '../../clients/vault/types';\n\nexport const isVariableEncryptionRequired = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('encrypted');\n\nexport const isVariableOauth = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('oauthCredentialsId');\n\nconst isSameAttributes = (\n a: CreateVariableBody['attributes'],\n b: CreateVariableBody['attributes'],\n): boolean => {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => a[k] === b[k]);\n};\n\nexport const isSameVariable = (a: AnyVariable, b: AnyVariable): boolean =>\n a.key === b.key && isSameAttributes(a.attributes, b.attributes);\n\nconst VAULT_REF_RE = /^\\{\\{ vault\\.(.+) \\}\\}$/;\n\nexport const vaultRef = {\n encode: (key: string): string => `{{ vault.${key} }}`,\n decode: (s: string): string | null => s.match(VAULT_REF_RE)?.[1] ?? null,\n isMatch: (s: string): boolean => VAULT_REF_RE.test(s),\n};\n\nexport const partitionByOauth = <T extends AnyVariable>(\n variables: T[],\n): { oauth: T[]; regular: T[] } =>\n variables.reduce<{ oauth: T[]; regular: T[] }>(\n (acc, variable) => {\n if (isVariableOauth(variable)) return { ...acc, oauth: [...acc.oauth, variable] };\n return { ...acc, regular: [...acc.regular, variable] };\n },\n { oauth: [], regular: [] },\n );\n","import type { EncryptQuery } from '../../clients/encryption/types';\nimport type { CreateVariableBody, VariableWithHash } from '../../clients/vault/types';\nimport { concurrent } from '../../utils';\n\nimport { isVariableEncryptionRequired } from './helpers';\nimport type { EncryptionClient, EncryptionCtx, VaultClient } from './types';\n\ntype Options = {\n vaultClient: VaultClient;\n encryptionClient: EncryptionClient;\n};\n\n// branchType is a property of each variable's own branchId, not of the batch — resolving it\n// here (rather than letting callers pre-compute one value) keeps a group write correct when it\n// spans branch scopes.\nconst resolveBranchType = (\n variable: CreateVariableBody,\n defaultBranchId: string,\n): EncryptQuery['branchType'] => {\n const branchId = variable.attributes?.branchId;\n if (!branchId) return null;\n return branchId === defaultBranchId ? 'default' : 'dev';\n};\n\n// The vault API rejects optional fields when they're present as empty strings — `group: ''`\n// and `attributes.branchId: ''` both 400 the request. The strict thing for an SDK to do is\n// throw and force callers to clean their input at the edge. We tolerate empties only because\n// kbc-ui's form state defaults un-filled text inputs to '' and the cost of fixing every form\n// submit to normalize before calling is too high right now. Remove this helper once the\n// caller side stops emitting empties — the SDK should ideally be strict about its inputs.\nconst stripEmptyOptionals = (body: CreateVariableBody): CreateVariableBody => {\n const { group, attributes, ...rest } = body;\n const { branchId, ...restAttrs } = attributes ?? {};\n return {\n ...rest,\n ...(group ? { group } : {}),\n attributes: branchId ? { ...restAttrs, branchId } : restAttrs,\n };\n};\n\nexport const createVaultSdk = ({ vaultClient, encryptionClient }: Options) => {\n const createVariable = async (variable: CreateVariableBody, encryption: EncryptionCtx) => {\n const body = stripEmptyOptionals(variable);\n\n const encryptedValue = isVariableEncryptionRequired(body)\n ? await encryptionClient.encrypt({\n projectId: encryption.projectId,\n data: body.value,\n branchType: resolveBranchType(body, encryption.defaultBranchId),\n })\n : body.value;\n\n return vaultClient.createVariable({ ...body, value: encryptedValue });\n };\n\n const deleteVariable = async (variable: VariableWithHash, signal?: AbortSignal) => {\n if (!variable.hash) throw new Error('Variable hash is missing');\n await vaultClient.deleteVariable(variable.hash, signal);\n };\n\n const updateVariable = async (\n variable: VariableWithHash,\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) => {\n await deleteVariable(variable, signal);\n return createVariable(variable, encryption);\n };\n\n const setVariablesGroup = async (\n group: string,\n variables: VariableWithHash[],\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) =>\n concurrent({\n items: variables,\n process: (variable) => updateVariable({ ...variable, group }, encryption, signal),\n concurrency: 3,\n });\n\n return {\n createVariable,\n deleteVariable,\n updateVariable,\n setVariablesGroup,\n };\n};\n"],"mappings":";;;AAEA,MAAa,gCAAgC,aAC3C,CAAC,CAAC,SAAS,OAAO,SAAS,WAAW;AAExC,MAAa,mBAAmB,aAC9B,CAAC,CAAC,SAAS,OAAO,SAAS,oBAAoB;AAEjD,MAAM,oBACJ,GACA,MACY;CACZ,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QAAQ,OAAO;CAC1C,OAAO,MAAM,OAAO,MAAM,EAAE,OAAO,EAAE,EAAE;AACzC;AAEA,MAAa,kBAAkB,GAAgB,MAC7C,EAAE,QAAQ,EAAE,OAAO,iBAAiB,EAAE,YAAY,EAAE,UAAU;AAEhE,MAAM,eAAe;AAErB,MAAa,WAAW;CACtB,SAAS,QAAwB,YAAY,IAAI;CACjD,SAAS,MAA6B,EAAE,MAAM,YAAY,CAAC,GAAG,MAAM;CACpE,UAAU,MAAuB,aAAa,KAAK,CAAC;AACtD;AAEA,MAAa,oBACX,cAEA,UAAU,QACP,KAAK,aAAa;CACjB,IAAI,gBAAgB,QAAQ,GAAG,OAAO;EAAE,GAAG;EAAK,OAAO,CAAC,GAAG,IAAI,OAAO,QAAQ;CAAE;CAChF,OAAO;EAAE,GAAG;EAAK,SAAS,CAAC,GAAG,IAAI,SAAS,QAAQ;CAAE;AACvD,GACA;CAAE,OAAO,CAAC;CAAG,SAAS,CAAC;AAAE,CAC3B;;ACvBF,MAAM,qBACJ,UACA,oBAC+B;CAC/B,MAAM,WAAW,SAAS,YAAY;CACtC,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,aAAa,kBAAkB,YAAY;AACpD;AAQA,MAAM,uBAAuB,SAAiD;CAC5E,MAAM,EAAE,OAAO,YAAY,GAAG,SAAS;CACvC,MAAM,EAAE,UAAU,GAAG,cAAc,cAAc,CAAC;CAClD,OAAO;EACL,GAAG;EACH,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,YAAY,WAAW;GAAE,GAAG;GAAW;EAAS,IAAI;CACtD;AACF;AAEA,MAAa,kBAAkB,EAAE,aAAa,uBAAgC;CAC5E,MAAM,iBAAiB,OAAO,UAA8B,eAA8B;EACxF,MAAM,OAAO,oBAAoB,QAAQ;EAEzC,MAAM,iBAAiB,6BAA6B,IAAI,IACpD,MAAM,iBAAiB,QAAQ;GAC7B,WAAW,WAAW;GACtB,MAAM,KAAK;GACX,YAAY,kBAAkB,MAAM,WAAW,eAAe;EAChE,CAAC,IACD,KAAK;EAET,OAAO,YAAY,eAAe;GAAE,GAAG;GAAM,OAAO;EAAe,CAAC;CACtE;CAEA,MAAM,iBAAiB,OAAO,UAA4B,WAAyB;EACjF,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,0BAA0B;EAC9D,MAAM,YAAY,eAAe,SAAS,MAAM,MAAM;CACxD;CAEA,MAAM,iBAAiB,OACrB,UACA,YACA,WACG;EACH,MAAM,eAAe,UAAU,MAAM;EACrC,OAAO,eAAe,UAAU,UAAU;CAC5C;CAEA,MAAM,oBAAoB,OACxB,OACA,WACA,YACA,WAEAA,mBAAAA,WAAW;EACT,OAAO;EACP,UAAU,aAAa,eAAe;GAAE,GAAG;GAAU;EAAM,GAAG,YAAY,MAAM;EAChF,aAAa;CACf,CAAC;CAEH,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"index.cjs","names":["concurrent"],"sources":["../../../src/sdks/vault/helpers.ts","../../../src/sdks/vault/vaultSdk.ts"],"sourcesContent":["import type { AnyVariable, CreateVariableBody } from '../../clients/vault/types';\n\nexport const isVariableEncryptionRequired = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('encrypted');\n\nexport const isVariableOauth = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('oauthCredentialsId');\n\nconst isSameAttributes = (\n a: CreateVariableBody['attributes'],\n b: CreateVariableBody['attributes'],\n): boolean => {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => a[k] === b[k]);\n};\n\nexport const isSameVariable = (a: AnyVariable, b: AnyVariable): boolean =>\n a.key === b.key && isSameAttributes(a.attributes, b.attributes);\n\nconst VAULT_REF_RE = /^\\{\\{ vault\\.(.+) \\}\\}$/;\n\nexport const vaultRef = {\n encode: (key: string): string => `{{ vault.${key} }}`,\n decode: (s: string): string | null => s.match(VAULT_REF_RE)?.[1] ?? null,\n isMatch: (s: string): boolean => VAULT_REF_RE.test(s),\n};\n\nexport const partitionByOauth = <T extends AnyVariable>(\n variables: T[],\n): { oauth: T[]; regular: T[] } => ({\n oauth: variables.filter((variable) => isVariableOauth(variable)),\n regular: variables.filter((variable) => !isVariableOauth(variable)),\n});\n","import type { EncryptQuery } from '../../clients/encryption/types';\nimport type { CreateVariableBody, VariableWithHash } from '../../clients/vault/types';\nimport { concurrent } from '../../utils';\n\nimport { isVariableEncryptionRequired } from './helpers';\nimport type { EncryptionClient, EncryptionCtx, VaultClient } from './types';\n\ntype Options = {\n vaultClient: VaultClient;\n encryptionClient: EncryptionClient;\n};\n\n// branchType is a property of each variable's own branchId, not of the batch — resolving it\n// here (rather than letting callers pre-compute one value) keeps a group write correct when it\n// spans branch scopes.\nconst resolveBranchType = (\n variable: CreateVariableBody,\n defaultBranchId: string,\n): EncryptQuery['branchType'] => {\n const branchId = variable.attributes?.branchId;\n if (!branchId) return null;\n return branchId === defaultBranchId ? 'default' : 'dev';\n};\n\n// The vault API rejects optional fields when they're present as empty strings — `group: ''`\n// and `attributes.branchId: ''` both 400 the request. The strict thing for an SDK to do is\n// throw and force callers to clean their input at the edge. We tolerate empties only because\n// kbc-ui's form state defaults un-filled text inputs to '' and the cost of fixing every form\n// submit to normalize before calling is too high right now. Remove this helper once the\n// caller side stops emitting empties — the SDK should ideally be strict about its inputs.\nconst stripEmptyOptionals = (body: CreateVariableBody): CreateVariableBody => {\n const { group, attributes, ...rest } = body;\n const { branchId, ...restAttrs } = attributes ?? {};\n return {\n ...rest,\n ...(group ? { group } : {}),\n attributes: branchId ? { ...restAttrs, branchId } : restAttrs,\n };\n};\n\nexport const createVaultSdk = ({ vaultClient, encryptionClient }: Options) => {\n const createVariable = async (variable: CreateVariableBody, encryption: EncryptionCtx) => {\n const body = stripEmptyOptionals(variable);\n\n const encryptedValue = isVariableEncryptionRequired(body)\n ? await encryptionClient.encrypt({\n projectId: encryption.projectId,\n data: body.value,\n branchType: resolveBranchType(body, encryption.defaultBranchId),\n })\n : body.value;\n\n return vaultClient.createVariable({ ...body, value: encryptedValue });\n };\n\n const deleteVariable = async (variable: VariableWithHash, signal?: AbortSignal) => {\n if (!variable.hash) throw new Error('Variable hash is missing');\n await vaultClient.deleteVariable(variable.hash, signal);\n };\n\n const updateVariable = async (\n variable: VariableWithHash,\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) => {\n await deleteVariable(variable, signal);\n return createVariable(variable, encryption);\n };\n\n const setVariablesGroup = async (\n group: string,\n variables: VariableWithHash[],\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) =>\n concurrent({\n items: variables,\n process: (variable) => updateVariable({ ...variable, group }, encryption, signal),\n concurrency: 3,\n });\n\n return {\n createVariable,\n deleteVariable,\n updateVariable,\n setVariablesGroup,\n };\n};\n"],"mappings":";;;AAEA,MAAa,gCAAgC,aAC3C,CAAC,CAAC,SAAS,OAAO,SAAS,WAAW;AAExC,MAAa,mBAAmB,aAC9B,CAAC,CAAC,SAAS,OAAO,SAAS,oBAAoB;AAEjD,MAAM,oBACJ,GACA,MACY;CACZ,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QAAQ,OAAO;CAC1C,OAAO,MAAM,OAAO,MAAM,EAAE,OAAO,EAAE,EAAE;AACzC;AAEA,MAAa,kBAAkB,GAAgB,MAC7C,EAAE,QAAQ,EAAE,OAAO,iBAAiB,EAAE,YAAY,EAAE,UAAU;AAEhE,MAAM,eAAe;AAErB,MAAa,WAAW;CACtB,SAAS,QAAwB,YAAY,IAAI;CACjD,SAAS,MAA6B,EAAE,MAAM,YAAY,CAAC,GAAG,MAAM;CACpE,UAAU,MAAuB,aAAa,KAAK,CAAC;AACtD;AAEA,MAAa,oBACX,eACkC;CAClC,OAAO,UAAU,QAAQ,aAAa,gBAAgB,QAAQ,CAAC;CAC/D,SAAS,UAAU,QAAQ,aAAa,CAAC,gBAAgB,QAAQ,CAAC;AACpE;;ACnBA,MAAM,qBACJ,UACA,oBAC+B;CAC/B,MAAM,WAAW,SAAS,YAAY;CACtC,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,aAAa,kBAAkB,YAAY;AACpD;AAQA,MAAM,uBAAuB,SAAiD;CAC5E,MAAM,EAAE,OAAO,YAAY,GAAG,SAAS;CACvC,MAAM,EAAE,UAAU,GAAG,cAAc,cAAc,CAAC;CAClD,OAAO;EACL,GAAG;EACH,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,YAAY,WAAW;GAAE,GAAG;GAAW;EAAS,IAAI;CACtD;AACF;AAEA,MAAa,kBAAkB,EAAE,aAAa,uBAAgC;CAC5E,MAAM,iBAAiB,OAAO,UAA8B,eAA8B;EACxF,MAAM,OAAO,oBAAoB,QAAQ;EAEzC,MAAM,iBAAiB,6BAA6B,IAAI,IACpD,MAAM,iBAAiB,QAAQ;GAC7B,WAAW,WAAW;GACtB,MAAM,KAAK;GACX,YAAY,kBAAkB,MAAM,WAAW,eAAe;EAChE,CAAC,IACD,KAAK;EAET,OAAO,YAAY,eAAe;GAAE,GAAG;GAAM,OAAO;EAAe,CAAC;CACtE;CAEA,MAAM,iBAAiB,OAAO,UAA4B,WAAyB;EACjF,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,0BAA0B;EAC9D,MAAM,YAAY,eAAe,SAAS,MAAM,MAAM;CACxD;CAEA,MAAM,iBAAiB,OACrB,UACA,YACA,WACG;EACH,MAAM,eAAe,UAAU,MAAM;EACrC,OAAO,eAAe,UAAU,UAAU;CAC5C;CAEA,MAAM,oBAAoB,OACxB,OACA,WACA,YACA,WAEAA,mBAAAA,WAAW;EACT,OAAO;EACP,UAAU,aAAa,eAAe;GAAE,GAAG;GAAU;EAAM,GAAG,YAAY,MAAM;EAChF,aAAa;CACf,CAAC;CAEH,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- import { _t as vaultRef, gt as partitionByOauth, ht as isVariableOauth, mt as isVariableEncryptionRequired, pt as isSameVariable, vt as createVaultSdk, yt as EncryptionCtx } from "../../index-BtvWJBYh.cjs";
1
+ import { _t as vaultRef, gt as partitionByOauth, ht as isVariableOauth, mt as isVariableEncryptionRequired, pt as isSameVariable, vt as createVaultSdk, yt as EncryptionCtx } from "../../index-CmyFWQXn.cjs";
2
2
  export { type EncryptionCtx, createVaultSdk, isSameVariable, isVariableEncryptionRequired, isVariableOauth, partitionByOauth, vaultRef };
@@ -1,2 +1,2 @@
1
- import { _t as vaultRef, gt as partitionByOauth, ht as isVariableOauth, mt as isVariableEncryptionRequired, pt as isSameVariable, vt as createVaultSdk, yt as EncryptionCtx } from "../../index-Df30jjpZ.js";
1
+ import { _t as vaultRef, gt as partitionByOauth, ht as isVariableOauth, mt as isVariableEncryptionRequired, pt as isSameVariable, vt as createVaultSdk, yt as EncryptionCtx } from "../../index-CQPs3hrp.js";
2
2
  export { type EncryptionCtx, createVaultSdk, isSameVariable, isVariableEncryptionRequired, isVariableOauth, partitionByOauth, vaultRef };
@@ -15,18 +15,9 @@ const vaultRef = {
15
15
  decode: (s) => s.match(VAULT_REF_RE)?.[1] ?? null,
16
16
  isMatch: (s) => VAULT_REF_RE.test(s)
17
17
  };
18
- const partitionByOauth = (variables) => variables.reduce((acc, variable) => {
19
- if (isVariableOauth(variable)) return {
20
- ...acc,
21
- oauth: [...acc.oauth, variable]
22
- };
23
- return {
24
- ...acc,
25
- regular: [...acc.regular, variable]
26
- };
27
- }, {
28
- oauth: [],
29
- regular: []
18
+ const partitionByOauth = (variables) => ({
19
+ oauth: variables.filter((variable) => isVariableOauth(variable)),
20
+ regular: variables.filter((variable) => !isVariableOauth(variable))
30
21
  });
31
22
  // src/sdks/vault/vaultSdk.ts
32
23
  const resolveBranchType = (variable, defaultBranchId) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/sdks/vault/helpers.ts","../../../src/sdks/vault/vaultSdk.ts"],"sourcesContent":["import type { AnyVariable, CreateVariableBody } from '../../clients/vault/types';\n\nexport const isVariableEncryptionRequired = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('encrypted');\n\nexport const isVariableOauth = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('oauthCredentialsId');\n\nconst isSameAttributes = (\n a: CreateVariableBody['attributes'],\n b: CreateVariableBody['attributes'],\n): boolean => {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => a[k] === b[k]);\n};\n\nexport const isSameVariable = (a: AnyVariable, b: AnyVariable): boolean =>\n a.key === b.key && isSameAttributes(a.attributes, b.attributes);\n\nconst VAULT_REF_RE = /^\\{\\{ vault\\.(.+) \\}\\}$/;\n\nexport const vaultRef = {\n encode: (key: string): string => `{{ vault.${key} }}`,\n decode: (s: string): string | null => s.match(VAULT_REF_RE)?.[1] ?? null,\n isMatch: (s: string): boolean => VAULT_REF_RE.test(s),\n};\n\nexport const partitionByOauth = <T extends AnyVariable>(\n variables: T[],\n): { oauth: T[]; regular: T[] } =>\n variables.reduce<{ oauth: T[]; regular: T[] }>(\n (acc, variable) => {\n if (isVariableOauth(variable)) return { ...acc, oauth: [...acc.oauth, variable] };\n return { ...acc, regular: [...acc.regular, variable] };\n },\n { oauth: [], regular: [] },\n );\n","import type { EncryptQuery } from '../../clients/encryption/types';\nimport type { CreateVariableBody, VariableWithHash } from '../../clients/vault/types';\nimport { concurrent } from '../../utils';\n\nimport { isVariableEncryptionRequired } from './helpers';\nimport type { EncryptionClient, EncryptionCtx, VaultClient } from './types';\n\ntype Options = {\n vaultClient: VaultClient;\n encryptionClient: EncryptionClient;\n};\n\n// branchType is a property of each variable's own branchId, not of the batch — resolving it\n// here (rather than letting callers pre-compute one value) keeps a group write correct when it\n// spans branch scopes.\nconst resolveBranchType = (\n variable: CreateVariableBody,\n defaultBranchId: string,\n): EncryptQuery['branchType'] => {\n const branchId = variable.attributes?.branchId;\n if (!branchId) return null;\n return branchId === defaultBranchId ? 'default' : 'dev';\n};\n\n// The vault API rejects optional fields when they're present as empty strings — `group: ''`\n// and `attributes.branchId: ''` both 400 the request. The strict thing for an SDK to do is\n// throw and force callers to clean their input at the edge. We tolerate empties only because\n// kbc-ui's form state defaults un-filled text inputs to '' and the cost of fixing every form\n// submit to normalize before calling is too high right now. Remove this helper once the\n// caller side stops emitting empties — the SDK should ideally be strict about its inputs.\nconst stripEmptyOptionals = (body: CreateVariableBody): CreateVariableBody => {\n const { group, attributes, ...rest } = body;\n const { branchId, ...restAttrs } = attributes ?? {};\n return {\n ...rest,\n ...(group ? { group } : {}),\n attributes: branchId ? { ...restAttrs, branchId } : restAttrs,\n };\n};\n\nexport const createVaultSdk = ({ vaultClient, encryptionClient }: Options) => {\n const createVariable = async (variable: CreateVariableBody, encryption: EncryptionCtx) => {\n const body = stripEmptyOptionals(variable);\n\n const encryptedValue = isVariableEncryptionRequired(body)\n ? await encryptionClient.encrypt({\n projectId: encryption.projectId,\n data: body.value,\n branchType: resolveBranchType(body, encryption.defaultBranchId),\n })\n : body.value;\n\n return vaultClient.createVariable({ ...body, value: encryptedValue });\n };\n\n const deleteVariable = async (variable: VariableWithHash, signal?: AbortSignal) => {\n if (!variable.hash) throw new Error('Variable hash is missing');\n await vaultClient.deleteVariable(variable.hash, signal);\n };\n\n const updateVariable = async (\n variable: VariableWithHash,\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) => {\n await deleteVariable(variable, signal);\n return createVariable(variable, encryption);\n };\n\n const setVariablesGroup = async (\n group: string,\n variables: VariableWithHash[],\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) =>\n concurrent({\n items: variables,\n process: (variable) => updateVariable({ ...variable, group }, encryption, signal),\n concurrency: 3,\n });\n\n return {\n createVariable,\n deleteVariable,\n updateVariable,\n setVariablesGroup,\n };\n};\n"],"mappings":";;AAEA,MAAa,gCAAgC,aAC3C,CAAC,CAAC,SAAS,OAAO,SAAS,WAAW;AAExC,MAAa,mBAAmB,aAC9B,CAAC,CAAC,SAAS,OAAO,SAAS,oBAAoB;AAEjD,MAAM,oBACJ,GACA,MACY;CACZ,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QAAQ,OAAO;CAC1C,OAAO,MAAM,OAAO,MAAM,EAAE,OAAO,EAAE,EAAE;AACzC;AAEA,MAAa,kBAAkB,GAAgB,MAC7C,EAAE,QAAQ,EAAE,OAAO,iBAAiB,EAAE,YAAY,EAAE,UAAU;AAEhE,MAAM,eAAe;AAErB,MAAa,WAAW;CACtB,SAAS,QAAwB,YAAY,IAAI;CACjD,SAAS,MAA6B,EAAE,MAAM,YAAY,CAAC,GAAG,MAAM;CACpE,UAAU,MAAuB,aAAa,KAAK,CAAC;AACtD;AAEA,MAAa,oBACX,cAEA,UAAU,QACP,KAAK,aAAa;CACjB,IAAI,gBAAgB,QAAQ,GAAG,OAAO;EAAE,GAAG;EAAK,OAAO,CAAC,GAAG,IAAI,OAAO,QAAQ;CAAE;CAChF,OAAO;EAAE,GAAG;EAAK,SAAS,CAAC,GAAG,IAAI,SAAS,QAAQ;CAAE;AACvD,GACA;CAAE,OAAO,CAAC;CAAG,SAAS,CAAC;AAAE,CAC3B;;ACvBF,MAAM,qBACJ,UACA,oBAC+B;CAC/B,MAAM,WAAW,SAAS,YAAY;CACtC,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,aAAa,kBAAkB,YAAY;AACpD;AAQA,MAAM,uBAAuB,SAAiD;CAC5E,MAAM,EAAE,OAAO,YAAY,GAAG,SAAS;CACvC,MAAM,EAAE,UAAU,GAAG,cAAc,cAAc,CAAC;CAClD,OAAO;EACL,GAAG;EACH,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,YAAY,WAAW;GAAE,GAAG;GAAW;EAAS,IAAI;CACtD;AACF;AAEA,MAAa,kBAAkB,EAAE,aAAa,uBAAgC;CAC5E,MAAM,iBAAiB,OAAO,UAA8B,eAA8B;EACxF,MAAM,OAAO,oBAAoB,QAAQ;EAEzC,MAAM,iBAAiB,6BAA6B,IAAI,IACpD,MAAM,iBAAiB,QAAQ;GAC7B,WAAW,WAAW;GACtB,MAAM,KAAK;GACX,YAAY,kBAAkB,MAAM,WAAW,eAAe;EAChE,CAAC,IACD,KAAK;EAET,OAAO,YAAY,eAAe;GAAE,GAAG;GAAM,OAAO;EAAe,CAAC;CACtE;CAEA,MAAM,iBAAiB,OAAO,UAA4B,WAAyB;EACjF,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,0BAA0B;EAC9D,MAAM,YAAY,eAAe,SAAS,MAAM,MAAM;CACxD;CAEA,MAAM,iBAAiB,OACrB,UACA,YACA,WACG;EACH,MAAM,eAAe,UAAU,MAAM;EACrC,OAAO,eAAe,UAAU,UAAU;CAC5C;CAEA,MAAM,oBAAoB,OACxB,OACA,WACA,YACA,WAEA,WAAW;EACT,OAAO;EACP,UAAU,aAAa,eAAe;GAAE,GAAG;GAAU;EAAM,GAAG,YAAY,MAAM;EAChF,aAAa;CACf,CAAC;CAEH,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/sdks/vault/helpers.ts","../../../src/sdks/vault/vaultSdk.ts"],"sourcesContent":["import type { AnyVariable, CreateVariableBody } from '../../clients/vault/types';\n\nexport const isVariableEncryptionRequired = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('encrypted');\n\nexport const isVariableOauth = (variable: AnyVariable): boolean =>\n !!variable.flags?.includes('oauthCredentialsId');\n\nconst isSameAttributes = (\n a: CreateVariableBody['attributes'],\n b: CreateVariableBody['attributes'],\n): boolean => {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => a[k] === b[k]);\n};\n\nexport const isSameVariable = (a: AnyVariable, b: AnyVariable): boolean =>\n a.key === b.key && isSameAttributes(a.attributes, b.attributes);\n\nconst VAULT_REF_RE = /^\\{\\{ vault\\.(.+) \\}\\}$/;\n\nexport const vaultRef = {\n encode: (key: string): string => `{{ vault.${key} }}`,\n decode: (s: string): string | null => s.match(VAULT_REF_RE)?.[1] ?? null,\n isMatch: (s: string): boolean => VAULT_REF_RE.test(s),\n};\n\nexport const partitionByOauth = <T extends AnyVariable>(\n variables: T[],\n): { oauth: T[]; regular: T[] } => ({\n oauth: variables.filter((variable) => isVariableOauth(variable)),\n regular: variables.filter((variable) => !isVariableOauth(variable)),\n});\n","import type { EncryptQuery } from '../../clients/encryption/types';\nimport type { CreateVariableBody, VariableWithHash } from '../../clients/vault/types';\nimport { concurrent } from '../../utils';\n\nimport { isVariableEncryptionRequired } from './helpers';\nimport type { EncryptionClient, EncryptionCtx, VaultClient } from './types';\n\ntype Options = {\n vaultClient: VaultClient;\n encryptionClient: EncryptionClient;\n};\n\n// branchType is a property of each variable's own branchId, not of the batch — resolving it\n// here (rather than letting callers pre-compute one value) keeps a group write correct when it\n// spans branch scopes.\nconst resolveBranchType = (\n variable: CreateVariableBody,\n defaultBranchId: string,\n): EncryptQuery['branchType'] => {\n const branchId = variable.attributes?.branchId;\n if (!branchId) return null;\n return branchId === defaultBranchId ? 'default' : 'dev';\n};\n\n// The vault API rejects optional fields when they're present as empty strings — `group: ''`\n// and `attributes.branchId: ''` both 400 the request. The strict thing for an SDK to do is\n// throw and force callers to clean their input at the edge. We tolerate empties only because\n// kbc-ui's form state defaults un-filled text inputs to '' and the cost of fixing every form\n// submit to normalize before calling is too high right now. Remove this helper once the\n// caller side stops emitting empties — the SDK should ideally be strict about its inputs.\nconst stripEmptyOptionals = (body: CreateVariableBody): CreateVariableBody => {\n const { group, attributes, ...rest } = body;\n const { branchId, ...restAttrs } = attributes ?? {};\n return {\n ...rest,\n ...(group ? { group } : {}),\n attributes: branchId ? { ...restAttrs, branchId } : restAttrs,\n };\n};\n\nexport const createVaultSdk = ({ vaultClient, encryptionClient }: Options) => {\n const createVariable = async (variable: CreateVariableBody, encryption: EncryptionCtx) => {\n const body = stripEmptyOptionals(variable);\n\n const encryptedValue = isVariableEncryptionRequired(body)\n ? await encryptionClient.encrypt({\n projectId: encryption.projectId,\n data: body.value,\n branchType: resolveBranchType(body, encryption.defaultBranchId),\n })\n : body.value;\n\n return vaultClient.createVariable({ ...body, value: encryptedValue });\n };\n\n const deleteVariable = async (variable: VariableWithHash, signal?: AbortSignal) => {\n if (!variable.hash) throw new Error('Variable hash is missing');\n await vaultClient.deleteVariable(variable.hash, signal);\n };\n\n const updateVariable = async (\n variable: VariableWithHash,\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) => {\n await deleteVariable(variable, signal);\n return createVariable(variable, encryption);\n };\n\n const setVariablesGroup = async (\n group: string,\n variables: VariableWithHash[],\n encryption: EncryptionCtx,\n signal?: AbortSignal,\n ) =>\n concurrent({\n items: variables,\n process: (variable) => updateVariable({ ...variable, group }, encryption, signal),\n concurrency: 3,\n });\n\n return {\n createVariable,\n deleteVariable,\n updateVariable,\n setVariablesGroup,\n };\n};\n"],"mappings":";;AAEA,MAAa,gCAAgC,aAC3C,CAAC,CAAC,SAAS,OAAO,SAAS,WAAW;AAExC,MAAa,mBAAmB,aAC9B,CAAC,CAAC,SAAS,OAAO,SAAS,oBAAoB;AAEjD,MAAM,oBACJ,GACA,MACY;CACZ,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QAAQ,OAAO;CAC1C,OAAO,MAAM,OAAO,MAAM,EAAE,OAAO,EAAE,EAAE;AACzC;AAEA,MAAa,kBAAkB,GAAgB,MAC7C,EAAE,QAAQ,EAAE,OAAO,iBAAiB,EAAE,YAAY,EAAE,UAAU;AAEhE,MAAM,eAAe;AAErB,MAAa,WAAW;CACtB,SAAS,QAAwB,YAAY,IAAI;CACjD,SAAS,MAA6B,EAAE,MAAM,YAAY,CAAC,GAAG,MAAM;CACpE,UAAU,MAAuB,aAAa,KAAK,CAAC;AACtD;AAEA,MAAa,oBACX,eACkC;CAClC,OAAO,UAAU,QAAQ,aAAa,gBAAgB,QAAQ,CAAC;CAC/D,SAAS,UAAU,QAAQ,aAAa,CAAC,gBAAgB,QAAQ,CAAC;AACpE;;ACnBA,MAAM,qBACJ,UACA,oBAC+B;CAC/B,MAAM,WAAW,SAAS,YAAY;CACtC,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,aAAa,kBAAkB,YAAY;AACpD;AAQA,MAAM,uBAAuB,SAAiD;CAC5E,MAAM,EAAE,OAAO,YAAY,GAAG,SAAS;CACvC,MAAM,EAAE,UAAU,GAAG,cAAc,cAAc,CAAC;CAClD,OAAO;EACL,GAAG;EACH,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,YAAY,WAAW;GAAE,GAAG;GAAW;EAAS,IAAI;CACtD;AACF;AAEA,MAAa,kBAAkB,EAAE,aAAa,uBAAgC;CAC5E,MAAM,iBAAiB,OAAO,UAA8B,eAA8B;EACxF,MAAM,OAAO,oBAAoB,QAAQ;EAEzC,MAAM,iBAAiB,6BAA6B,IAAI,IACpD,MAAM,iBAAiB,QAAQ;GAC7B,WAAW,WAAW;GACtB,MAAM,KAAK;GACX,YAAY,kBAAkB,MAAM,WAAW,eAAe;EAChE,CAAC,IACD,KAAK;EAET,OAAO,YAAY,eAAe;GAAE,GAAG;GAAM,OAAO;EAAe,CAAC;CACtE;CAEA,MAAM,iBAAiB,OAAO,UAA4B,WAAyB;EACjF,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,0BAA0B;EAC9D,MAAM,YAAY,eAAe,SAAS,MAAM,MAAM;CACxD;CAEA,MAAM,iBAAiB,OACrB,UACA,YACA,WACG;EACH,MAAM,eAAe,UAAU,MAAM;EACrC,OAAO,eAAe,UAAU,UAAU;CAC5C;CAEA,MAAM,oBAAoB,OACxB,OACA,WACA,YACA,WAEA,WAAW;EACT,OAAO;EACP,UAAU,aAAa,eAAe;GAAE,GAAG;GAAU;EAAM,GAAG,YAAY,MAAM;EAChF,aAAa;CACf,CAAC;CAEH,OAAO;EACL;EACA;EACA;EACA;CACF;AACF"}
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_UserError = require("../UserError-D4P9Tbhf.cjs");
3
3
  const require_createFetchClient = require("../createFetchClient-CDKSkd7i.cjs");
4
4
  const require_validateConnectionStatus = require("../validateConnectionStatus-ckaHcRx8.cjs");
5
- const require_storage = require("../storage-BMrYlyLB.cjs");
5
+ const require_storage = require("../storage-BL-TfHp8.cjs");
6
6
  const require_ManagementSessionMintError = require("../ManagementSessionMintError-Bc9bc7Ai.cjs");
7
7
  const require_RowLevelSecurityError = require("../RowLevelSecurityError-RK_NhhAx.cjs");
8
8
  const require_QueueJobError = require("../QueueJobError-DruZK3tc.cjs");
@@ -1,4 +1,4 @@
1
1
  import { Br as QueueJobError, C as isValidationError, E as isStorageJobError, Rr as RowLevelSecurityError, S as formatValidationIssues, T as StorageJobError, Vr as isQueueJobError, _ as isAbortError, g as FetchClientError, ii as manageErrorCode, ni as ManagementClientAuthError, oi as HtmlResponseError, pi as ApiError, ri as isManageError, si as isHtmlResponseError, ti as ManagementSessionMintError, v as isApiError, w as parseOrThrow, x as ValidationError, y as isFetchClientError, zr as isRowLevelSecurityError } from "../index-FrsEkDvX.cjs";
2
- import { As as QueryJobError, Ds as ServiceUnavailableError, Es as isSyncActionError, Ms as UserError, Os as retryAfterSeconds, Ts as SyncActionError, _ as StorageGenericFetchClient, js as isQueryJobError, ks as readableReason, v as StorageOpenApiFetchClient, y as createStorageClient } from "../index-BtvWJBYh.cjs";
3
- import { n as toBackendSubscribers, r as isSqlWorkspaceConnection, t as fromBackendSubscribers } from "../index-B04rWq_0.cjs";
2
+ import { As as QueryJobError, Ds as ServiceUnavailableError, Es as isSyncActionError, Ms as UserError, Os as retryAfterSeconds, Ts as SyncActionError, _ as StorageGenericFetchClient, js as isQueryJobError, ks as readableReason, v as StorageOpenApiFetchClient, y as createStorageClient } from "../index-CmyFWQXn.cjs";
3
+ import { n as toBackendSubscribers, r as isSqlWorkspaceConnection, t as fromBackendSubscribers } from "../index-CWowDl63.cjs";
4
4
  export { ApiError, type FetchClientError, HtmlResponseError, ManagementClientAuthError, ManagementSessionMintError, QueryJobError, QueueJobError, RowLevelSecurityError, ServiceUnavailableError, StorageGenericFetchClient, StorageJobError, StorageOpenApiFetchClient, SyncActionError, UserError, ValidationError, createStorageClient, formatValidationIssues, fromBackendSubscribers, isAbortError, isApiError, isFetchClientError, isHtmlResponseError, isManageError, isQueryJobError, isQueueJobError, isRowLevelSecurityError, isSqlWorkspaceConnection, isStorageJobError, isSyncActionError, isValidationError, manageErrorCode, parseOrThrow, readableReason, retryAfterSeconds, toBackendSubscribers };
@@ -1,4 +1,4 @@
1
1
  import { Br as QueueJobError, C as isValidationError, E as isStorageJobError, Rr as RowLevelSecurityError, S as formatValidationIssues, T as StorageJobError, Vr as isQueueJobError, _ as isAbortError, g as FetchClientError, ii as manageErrorCode, ni as ManagementClientAuthError, oi as HtmlResponseError, pi as ApiError, ri as isManageError, si as isHtmlResponseError, ti as ManagementSessionMintError, v as isApiError, w as parseOrThrow, x as ValidationError, y as isFetchClientError, zr as isRowLevelSecurityError } from "../index-FrsEkDvX.js";
2
- import { As as QueryJobError, Ds as ServiceUnavailableError, Es as isSyncActionError, Ms as UserError, Os as retryAfterSeconds, Ts as SyncActionError, _ as StorageGenericFetchClient, js as isQueryJobError, ks as readableReason, v as StorageOpenApiFetchClient, y as createStorageClient } from "../index-Df30jjpZ.js";
3
- import { n as toBackendSubscribers, r as isSqlWorkspaceConnection, t as fromBackendSubscribers } from "../index-DCfumWzq.js";
2
+ import { As as QueryJobError, Ds as ServiceUnavailableError, Es as isSyncActionError, Ms as UserError, Os as retryAfterSeconds, Ts as SyncActionError, _ as StorageGenericFetchClient, js as isQueryJobError, ks as readableReason, v as StorageOpenApiFetchClient, y as createStorageClient } from "../index-CQPs3hrp.js";
3
+ import { n as toBackendSubscribers, r as isSqlWorkspaceConnection, t as fromBackendSubscribers } from "../index-BGsP2QBc.js";
4
4
  export { ApiError, type FetchClientError, HtmlResponseError, ManagementClientAuthError, ManagementSessionMintError, QueryJobError, QueueJobError, RowLevelSecurityError, ServiceUnavailableError, StorageGenericFetchClient, StorageJobError, StorageOpenApiFetchClient, SyncActionError, UserError, ValidationError, createStorageClient, formatValidationIssues, fromBackendSubscribers, isAbortError, isApiError, isFetchClientError, isHtmlResponseError, isManageError, isQueryJobError, isQueueJobError, isRowLevelSecurityError, isSqlWorkspaceConnection, isStorageJobError, isSyncActionError, isValidationError, manageErrorCode, parseOrThrow, readableReason, retryAfterSeconds, toBackendSubscribers };
@@ -1,7 +1,7 @@
1
1
  import { t as UserError } from "../UserError-BxoOJJ_u.js";
2
2
  import { i as isFetchClientError, n as isAbortError, p as ApiError, r as isApiError } from "../createFetchClient-Dc_ZMuq7.js";
3
3
  import { n as HtmlResponseError, r as isHtmlResponseError } from "../validateConnectionStatus-DV00sDmu.js";
4
- import { c as ServiceUnavailableError, d as isManageError, f as manageErrorCode, i as toBackendSubscribers, l as retryAfterSeconds, n as isSqlWorkspaceConnection, o as StorageJobError, r as fromBackendSubscribers, s as isStorageJobError, t as createStorageClient, u as readableReason } from "../storage--2FvvLAw.js";
4
+ import { c as ServiceUnavailableError, d as isManageError, f as manageErrorCode, i as toBackendSubscribers, l as retryAfterSeconds, n as isSqlWorkspaceConnection, o as StorageJobError, r as fromBackendSubscribers, s as isStorageJobError, t as createStorageClient, u as readableReason } from "../storage-DEJN8sw-.js";
5
5
  import { n as ManagementClientAuthError, t as ManagementSessionMintError } from "../ManagementSessionMintError-BMHDcEqV.js";
6
6
  import { i as isQueryJobError, n as isRowLevelSecurityError, r as QueryJobError, t as RowLevelSecurityError } from "../RowLevelSecurityError-CObFqj3E.js";
7
7
  import { n as isQueueJobError, t as QueueJobError } from "../QueueJobError-BJNUINXW.js";