@stndrds/schema 1.0.0-alpha.91 → 1.0.0-alpha.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -252,7 +252,10 @@ function isFlowFieldsRow(row) {
252
252
  return !row.type || row.type === "fields";
253
253
  }
254
254
  function isLayoutRow(row) {
255
- return !!row.type && row.type !== "fields";
255
+ return !!row.type && row.type !== "fields" && row.type !== "relationList";
256
+ }
257
+ function isFlowRelationListRow(row) {
258
+ return row.type === "relationList";
256
259
  }
257
260
  function isFlowDefinition(obj) {
258
261
  return typeof obj === "object" && obj !== null && "slots" in obj && "pages" in obj && "relations" in obj && "status" in obj;
@@ -294,7 +297,9 @@ var RESERVED_ATTRIBUTE_NAMES = [
294
297
  "completionStatus",
295
298
  "values",
296
299
  "metadata",
297
- "deletedAt"
300
+ "deletedAt",
301
+ "schemaVersion",
302
+ "archivedValues"
298
303
  ];
299
304
 
300
305
  // src/types/permissions.ts
@@ -858,7 +863,8 @@ function createEmptyContext() {
858
863
  documents: {},
859
864
  variables: {},
860
865
  conditionResults: {},
861
- createdRecordIds: {}
866
+ createdRecordIds: {},
867
+ relationBuffers: {}
862
868
  };
863
869
  }
864
870
  function getContextValue(context, path) {
@@ -1316,6 +1322,14 @@ var WorkflowDefinitionSchema = z.object({
1316
1322
  }
1317
1323
  );
1318
1324
 
1325
+ // src/types/migrations.ts
1326
+ var DEFAULT_RETENTION_POLICY = {
1327
+ attributeData: 30,
1328
+ deletedObjects: 90,
1329
+ transforms: 365,
1330
+ migrationErrors: 30
1331
+ };
1332
+
1319
1333
  // src/lib/object-helpers.ts
1320
1334
  function isEmpty2(obj) {
1321
1335
  if (obj === null || obj === void 0) {
@@ -2834,8 +2848,146 @@ function document(config) {
2834
2848
 
2835
2849
  // src/builders/object-builder.ts
2836
2850
  import z2 from "zod";
2851
+
2852
+ // src/builders/migration-builder.ts
2853
+ function resolveBuiltInTransform(targetType) {
2854
+ const map = {
2855
+ text: "toString",
2856
+ textarea: "toString",
2857
+ richtext: "toString",
2858
+ number: "toNumber",
2859
+ currency: "toNumber",
2860
+ rating: "toNumber",
2861
+ date: "toDate",
2862
+ checkbox: "toBoolean"
2863
+ };
2864
+ return map[targetType];
2865
+ }
2866
+ function reverseOperation(op) {
2867
+ switch (op.type) {
2868
+ case "rename_attribute":
2869
+ return { type: "rename_attribute", from: op.to, to: op.from };
2870
+ case "add_attribute":
2871
+ return { type: "remove_attribute", name: op.attribute.name, backup_config: op.attribute };
2872
+ case "remove_attribute":
2873
+ return { type: "add_attribute", attribute: op.backup_config };
2874
+ case "change_type":
2875
+ return {
2876
+ type: "change_type",
2877
+ name: op.name,
2878
+ from: op.to,
2879
+ to: op.from,
2880
+ transform: op.transform ? resolveBuiltInTransform(op.from) : void 0
2881
+ };
2882
+ case "update_config":
2883
+ return { type: "update_config", name: op.name, from: op.to, to: op.from };
2884
+ case "rename_object":
2885
+ return { type: "rename_object", from: op.to, to: op.from };
2886
+ case "remove_object":
2887
+ return { type: "remove_object", backup: op.backup };
2888
+ }
2889
+ }
2890
+ var MigrationBuilder = class {
2891
+ constructor(version) {
2892
+ this.operations = [];
2893
+ /** Tracks attribute names that have already been referenced in this migration */
2894
+ this.touchedAttributes = /* @__PURE__ */ new Set();
2895
+ this.version = version;
2896
+ }
2897
+ // --------------------------------------------------------------------------
2898
+ // CONFLICT GUARD
2899
+ // --------------------------------------------------------------------------
2900
+ assertNotTouched(name, operationType) {
2901
+ if (this.touchedAttributes.has(name)) {
2902
+ throw new Error(
2903
+ `[MigrationBuilder] Conflicting operations on attribute "${name}": it was already modified earlier in this migration (attempted: ${operationType}).`
2904
+ );
2905
+ }
2906
+ }
2907
+ // --------------------------------------------------------------------------
2908
+ // OPERATION METHODS
2909
+ // --------------------------------------------------------------------------
2910
+ /**
2911
+ * Rename an attribute.
2912
+ * The reverse operation will rename it back.
2913
+ */
2914
+ renameAttribute(from, to) {
2915
+ this.assertNotTouched(from, "rename_attribute");
2916
+ this.touchedAttributes.add(from);
2917
+ this.operations.push({ type: "rename_attribute", from, to });
2918
+ return this;
2919
+ }
2920
+ /**
2921
+ * Change the type of an attribute.
2922
+ *
2923
+ * The `transform` option accepts a function — it is used only to signal
2924
+ * intent; the actual built-in transform is resolved from the target type.
2925
+ */
2926
+ changeType(name, from, to, options) {
2927
+ this.assertNotTouched(name, "change_type");
2928
+ this.touchedAttributes.add(name);
2929
+ const transform = options?.transform ? resolveBuiltInTransform(to) : void 0;
2930
+ this.operations.push({ type: "change_type", name, from, to, transform });
2931
+ return this;
2932
+ }
2933
+ /**
2934
+ * Remove an attribute.
2935
+ *
2936
+ * The `backup_config` is intentionally left empty — the sync engine will
2937
+ * populate it from current DB state before applying the migration.
2938
+ */
2939
+ removeAttribute(name) {
2940
+ this.assertNotTouched(name, "remove_attribute");
2941
+ this.touchedAttributes.add(name);
2942
+ this.operations.push({
2943
+ type: "remove_attribute",
2944
+ name,
2945
+ backup_config: {}
2946
+ });
2947
+ return this;
2948
+ }
2949
+ /**
2950
+ * Add a new attribute.
2951
+ * The reverse operation will remove it (using the attribute definition as backup).
2952
+ */
2953
+ addAttribute(attribute) {
2954
+ this.assertNotTouched(attribute.name, "add_attribute");
2955
+ this.touchedAttributes.add(attribute.name);
2956
+ this.operations.push({ type: "add_attribute", attribute });
2957
+ return this;
2958
+ }
2959
+ /**
2960
+ * Update the configuration of an attribute (partial patch).
2961
+ *
2962
+ * The `from` config is intentionally left empty — the sync engine will
2963
+ * populate it from current DB state before applying the migration.
2964
+ */
2965
+ updateConfig(name, config) {
2966
+ this.assertNotTouched(name, "update_config");
2967
+ this.touchedAttributes.add(name);
2968
+ this.operations.push({ type: "update_config", name, from: {}, to: config });
2969
+ return this;
2970
+ }
2971
+ // --------------------------------------------------------------------------
2972
+ // BUILD
2973
+ // --------------------------------------------------------------------------
2974
+ /**
2975
+ * Produce the final MigrationDefinition with auto-generated reverse operations.
2976
+ */
2977
+ build() {
2978
+ const reverse_operations = [...this.operations].reverse().map((op) => reverseOperation(op));
2979
+ return {
2980
+ version: this.version,
2981
+ operations: [...this.operations],
2982
+ reverse_operations
2983
+ };
2984
+ }
2985
+ };
2986
+
2987
+ // src/builders/object-builder.ts
2837
2988
  var ObjectBuilder = class {
2838
2989
  constructor(config) {
2990
+ this._migrations = [];
2839
2991
  this.validateName(config.name);
2840
2992
  this.obj = {
2841
2993
  name: config.name,
@@ -2932,6 +3084,37 @@ var ObjectBuilder = class {
2932
3084
  this._labelExpression = template;
2933
3085
  return this;
2934
3086
  }
3087
+ /**
3088
+ * Declare a schema migration for this object.
3089
+ *
3090
+ * - `version` must be >= 2 (version 1 is implicit — no migration needed).
3091
+ * - Versions must be declared in sequential order without gaps or duplicates.
3092
+ * - The callback receives a MigrationBuilder; call `.build()` is not required
3093
+ * (the ObjectBuilder calls it internally).
3094
+ *
3095
+ * @example
3096
+ * ```typescript
3097
+ * object({ name: "contacts", label: "Contact" })
3098
+ * .migration(2, (m) => m.renameAttribute("firstName", "first_name"))
3099
+ * .migration(3, (m) => m.changeType("age", "text", "number"))
3100
+ * .labelExpression("{{ first_name }}")
3101
+ * ```
3102
+ */
3103
+ migration(version, callback) {
3104
+ if (version < 2) {
3105
+ throw new Error(
3106
+ `[ObjectBuilder] Migration version must be >= 2 (version 1 is implicit). Got: ${version}`
3107
+ );
3108
+ }
3109
+ const isDuplicate = this._migrations.some((m) => m.version === version);
3110
+ if (isDuplicate) {
3111
+ throw new Error(`[ObjectBuilder] Duplicate migration version: ${version}`);
3112
+ }
3113
+ const builder = new MigrationBuilder(version);
3114
+ callback(builder);
3115
+ this._migrations.push(builder.build());
3116
+ return this;
3117
+ }
2935
3118
  /**
2936
3119
  * Build the final ObjectDefinition
2937
3120
  * @throws Error if required fields are missing or invalid
@@ -2951,10 +3134,22 @@ The labelExpression defines how records are displayed in lists and relations.
2951
3134
  \u2705 Example: .labelExpression("{{ firstName }} {{ lastName }}")`
2952
3135
  );
2953
3136
  }
3137
+ const sortedVersions = [...this._migrations].sort((a, b) => a.version - b.version);
3138
+ for (let i = 0; i < sortedVersions.length; i++) {
3139
+ const expected = i + 2;
3140
+ if (sortedVersions[i].version !== expected) {
3141
+ throw new Error(
3142
+ `[ObjectBuilder] Migration versions must be sequential starting at 2. Expected version ${expected}, got ${sortedVersions[i].version}.`
3143
+ );
3144
+ }
3145
+ }
3146
+ const schema_version = sortedVersions.length > 0 ? sortedVersions[sortedVersions.length - 1].version : 1;
2954
3147
  return {
2955
3148
  ...this.obj,
2956
3149
  pluralLabel: this._pluralLabel,
2957
- labelExpression: this._labelExpression
3150
+ labelExpression: this._labelExpression,
3151
+ schema_version,
3152
+ migrations: sortedVersions
2958
3153
  };
2959
3154
  }
2960
3155
  /**
@@ -3622,6 +3817,7 @@ var TabBuilder = class {
3622
3817
  };
3623
3818
  var DetailViewBuilder = class {
3624
3819
  constructor(name, label) {
3820
+ this._version = 1;
3625
3821
  this.validateName(name);
3626
3822
  this.data = {
3627
3823
  name,
@@ -3683,6 +3879,17 @@ var DetailViewBuilder = class {
3683
3879
  this.data.metadata = value;
3684
3880
  return this;
3685
3881
  }
3882
+ /**
3883
+ * Set the schema version for this view definition.
3884
+ * Increment when making breaking changes to force client updates.
3885
+ * @param v - Version number (must be >= 1)
3886
+ * @default 1
3887
+ */
3888
+ version(v) {
3889
+ if (v < 1) throw new Error("View version must be >= 1");
3890
+ this._version = v;
3891
+ return this;
3892
+ }
3686
3893
  /**
3687
3894
  * Configure a side panel with flat attribute fields displayed alongside tab content.
3688
3895
  * Not available for modal layout.
@@ -3755,7 +3962,8 @@ var DetailViewBuilder = class {
3755
3962
  type: "detail",
3756
3963
  config,
3757
3964
  default: this.data.default,
3758
- metadata: this.data.metadata
3965
+ metadata: this.data.metadata,
3966
+ schema_version: this._version
3759
3967
  };
3760
3968
  }
3761
3969
  /**
@@ -3784,6 +3992,7 @@ function view(name, label) {
3784
3992
  }
3785
3993
  var ListViewBuilder = class {
3786
3994
  constructor(name, label) {
3995
+ this._version = 1;
3787
3996
  this.validateName(name);
3788
3997
  this.data = {
3789
3998
  name,
@@ -3827,6 +4036,17 @@ var ListViewBuilder = class {
3827
4036
  this.data.metadata = value;
3828
4037
  return this;
3829
4038
  }
4039
+ /**
4040
+ * Set the schema version for this view definition.
4041
+ * Increment when making breaking changes to force client updates.
4042
+ * @param v - Version number (must be >= 1)
4043
+ * @default 1
4044
+ */
4045
+ version(v) {
4046
+ if (v < 1) throw new Error("View version must be >= 1");
4047
+ this._version = v;
4048
+ return this;
4049
+ }
3830
4050
  /**
3831
4051
  * Set base filters applied to ALL tabs (scoping, tenant, etc.)
3832
4052
  * @example .baseFilter({ combinator: "and", rules: [{ attribute: "tenant", operator: "is", value: "acme" }] })
@@ -3922,7 +4142,8 @@ var ListViewBuilder = class {
3922
4142
  type: "list",
3923
4143
  config,
3924
4144
  default: this.data.default,
3925
- metadata: this.data.metadata
4145
+ metadata: this.data.metadata,
4146
+ schema_version: this._version
3926
4147
  };
3927
4148
  }
3928
4149
  /**
@@ -4264,14 +4485,42 @@ var WorkflowFormBuilder = class {
4264
4485
  this.rows.push(row);
4265
4486
  return this;
4266
4487
  }
4488
+ /**
4489
+ * Add a relation list row to the form.
4490
+ * Renders an editable list of related records for a given slot and relation.
4491
+ *
4492
+ * @param id - Unique row identifier
4493
+ * @param slotId - The slot containing the relation
4494
+ * @param relationName - The relation attribute name
4495
+ * @param options - Display and preload options
4496
+ */
4497
+ relationListField(id, slotId, relationName, options = {}) {
4498
+ this.rowOrder++;
4499
+ const row = {
4500
+ id,
4501
+ order: this.rowOrder,
4502
+ type: "relationList",
4503
+ slotId,
4504
+ relationName,
4505
+ preload: options.preload ?? true,
4506
+ columns: options.columns ?? [],
4507
+ qualifiersInline: options.qualifiersInline ?? true,
4508
+ modalFields: options.modalFields ?? "all",
4509
+ label: options.label
4510
+ };
4511
+ this.rows.push(row);
4512
+ return this;
4513
+ }
4267
4514
  /**
4268
4515
  * Set the next node and complete the form definition
4269
4516
  */
4270
4517
  next(nodeId) {
4271
- const hasFieldRows = this.rows.some((r) => !r.type || r.type === "fields");
4518
+ const hasFieldRows = this.rows.some(
4519
+ (r) => !r.type || r.type === "fields" || r.type === "relationList"
4520
+ );
4272
4521
  if (!hasFieldRows) {
4273
4522
  throw new Error(
4274
- `[WorkflowBuilder] Form "${this.nodeId}" has no field rows. Use .row() to add fields.`
4523
+ `[WorkflowBuilder] Form "${this.nodeId}" has no field rows. Use .row() or .relationListField() to add fields.`
4275
4524
  );
4276
4525
  }
4277
4526
  return this.workflowBuilder._addFormNode({
@@ -5809,7 +6058,8 @@ function generateDefaultDetailView(object2, options = {}) {
5809
6058
  object: object2.name,
5810
6059
  type: "detail",
5811
6060
  config,
5812
- default: true
6061
+ default: true,
6062
+ schema_version: 1
5813
6063
  };
5814
6064
  }
5815
6065
  function generateDefaultListView(object2, options = {}) {
@@ -5834,7 +6084,8 @@ function generateDefaultListView(object2, options = {}) {
5834
6084
  object: object2.name,
5835
6085
  type: "list",
5836
6086
  config,
5837
- default: true
6087
+ default: true,
6088
+ schema_version: 1
5838
6089
  };
5839
6090
  }
5840
6091
  function generateFallbackView(object2, type, options = {}) {
@@ -6020,6 +6271,7 @@ export {
6020
6271
  CreateShareInputSchema,
6021
6272
  CustomTabConfig,
6022
6273
  DEFAULT_LABEL_FALLBACK,
6274
+ DEFAULT_RETENTION_POLICY,
6023
6275
  DEFAULT_ROLES,
6024
6276
  DEFAULT_ROLE_DESCRIPTIONS,
6025
6277
  DEFAULT_ROLE_FOR_NEW_USERS,
@@ -6212,6 +6464,7 @@ export {
6212
6464
  isFlowDefinition,
6213
6465
  isFlowFieldsRow,
6214
6466
  isFlowPublished,
6467
+ isFlowRelationListRow,
6215
6468
  isFlowsTab,
6216
6469
  isForbiddenError,
6217
6470
  isFormFieldsRow,
@@ -1,4 +1,4 @@
1
1
  import 'zod';
2
- export { Q as DEFAULT_VALIDATION_MESSAGES, ac as ValidationMessages, ad as ValidationResult, ae as attributeConfigSchemas, af as checkboxConfigSchema, ag as computeRecordStatus, ah as createAttributeValidator, ai as createCheckboxValidator, aj as createCurrencyValidator, ak as createDateValidator, al as createDraftValidator, am as createFileValidator, an as createFormAttributeValidator, ao as createFormulaValidator, ap as createLocationValidator, aq as createMultiRelationValidator, ar as createMultiselectValidator, as as createNumberValidator, at as createObjectValidator, au as createPhoneValidator, av as createRatingValidator, aw as createRelationValidator, ax as createRichtextValidator, ay as createRollupValidator, az as createSelectValidator, aA as createSingleRelationValidator, aB as createStatusValidator, aC as createTextAreaValidator, aD as createTextValidator, aE as createUserValidator, aF as currencyConfigSchema, aG as dateConfigSchema, aH as documentConfigSchema, aI as fileConfigSchema, aJ as formatZodErrors, aK as formulaConfigSchema, aL as getAttributeConfigSchema, aM as getMissingRequiredAttributes, aR as isRecordComplete, aT as locationConfigSchema, aU as multiselectConfigSchema, aV as numberConfigSchema, aW as parseAttributeConfig, aX as phoneConfigSchema, aY as ratingConfigSchema, aZ as relationConfigSchema, a_ as richtextConfigSchema, a$ as rollupConfigSchema, b0 as safeParseAttributeConfig, b1 as selectConfigSchema, b2 as statusConfigSchema, b3 as textConfigSchema, b4 as textareaConfigSchema, b5 as userConfigSchema, b6 as validateAttribute, b7 as validateAttributeConfig, b8 as validateDraft, b9 as validateDraftOrThrow, ba as validateObject, bb as validateObjectOrThrow } from '../validators-BFgj3O3w.mjs';
2
+ export { aV as DEFAULT_VALIDATION_MESSAGES, ca as ValidationMessages, cb as ValidationResult, ci as attributeConfigSchemas, ck as checkboxConfigSchema, cl as computeRecordStatus, cm as createAttributeValidator, cn as createCheckboxValidator, co as createCurrencyValidator, cp as createDateValidator, cq as createDraftValidator, cs as createFileValidator, ct as createFormAttributeValidator, cu as createFormulaValidator, cv as createLocationValidator, cw as createMultiRelationValidator, cx as createMultiselectValidator, cy as createNumberValidator, cz as createObjectValidator, cA as createPhoneValidator, cB as createRatingValidator, cC as createRelationValidator, cD as createRichtextValidator, cE as createRollupValidator, cF as createSelectValidator, cG as createSingleRelationValidator, cI as createStatusValidator, cJ as createTextAreaValidator, cK as createTextValidator, cL as createUserValidator, cM as currencyConfigSchema, cN as dateConfigSchema, cO as documentConfigSchema, cQ as fileConfigSchema, cR as formatZodErrors, cS as formulaConfigSchema, cU as getAttributeConfigSchema, cW as getMissingRequiredAttributes, dt as isRecordComplete, dG as locationConfigSchema, dI as multiselectConfigSchema, dK as numberConfigSchema, dM as parseAttributeConfig, dN as phoneConfigSchema, dO as ratingConfigSchema, dP as relationConfigSchema, dQ as richtextConfigSchema, dR as rollupConfigSchema, dS as safeParseAttributeConfig, dT as selectConfigSchema, dV as statusConfigSchema, dW as textConfigSchema, dX as textareaConfigSchema, dY as userConfigSchema, dZ as validateAttribute, d_ as validateAttributeConfig, d$ as validateDraft, e0 as validateDraftOrThrow, e1 as validateObject, e2 as validateObjectOrThrow } from '../validators-CwhyfvP7.mjs';
3
3
  import '@stndrds/constants';
4
4
  import '../utils.mjs';
@@ -1,4 +1,4 @@
1
1
  import 'zod';
2
- export { Q as DEFAULT_VALIDATION_MESSAGES, ac as ValidationMessages, ad as ValidationResult, ae as attributeConfigSchemas, af as checkboxConfigSchema, ag as computeRecordStatus, ah as createAttributeValidator, ai as createCheckboxValidator, aj as createCurrencyValidator, ak as createDateValidator, al as createDraftValidator, am as createFileValidator, an as createFormAttributeValidator, ao as createFormulaValidator, ap as createLocationValidator, aq as createMultiRelationValidator, ar as createMultiselectValidator, as as createNumberValidator, at as createObjectValidator, au as createPhoneValidator, av as createRatingValidator, aw as createRelationValidator, ax as createRichtextValidator, ay as createRollupValidator, az as createSelectValidator, aA as createSingleRelationValidator, aB as createStatusValidator, aC as createTextAreaValidator, aD as createTextValidator, aE as createUserValidator, aF as currencyConfigSchema, aG as dateConfigSchema, aH as documentConfigSchema, aI as fileConfigSchema, aJ as formatZodErrors, aK as formulaConfigSchema, aL as getAttributeConfigSchema, aM as getMissingRequiredAttributes, aR as isRecordComplete, aT as locationConfigSchema, aU as multiselectConfigSchema, aV as numberConfigSchema, aW as parseAttributeConfig, aX as phoneConfigSchema, aY as ratingConfigSchema, aZ as relationConfigSchema, a_ as richtextConfigSchema, a$ as rollupConfigSchema, b0 as safeParseAttributeConfig, b1 as selectConfigSchema, b2 as statusConfigSchema, b3 as textConfigSchema, b4 as textareaConfigSchema, b5 as userConfigSchema, b6 as validateAttribute, b7 as validateAttributeConfig, b8 as validateDraft, b9 as validateDraftOrThrow, ba as validateObject, bb as validateObjectOrThrow } from '../validators-C7i6EpQK.js';
2
+ export { aV as DEFAULT_VALIDATION_MESSAGES, ca as ValidationMessages, cb as ValidationResult, ci as attributeConfigSchemas, ck as checkboxConfigSchema, cl as computeRecordStatus, cm as createAttributeValidator, cn as createCheckboxValidator, co as createCurrencyValidator, cp as createDateValidator, cq as createDraftValidator, cs as createFileValidator, ct as createFormAttributeValidator, cu as createFormulaValidator, cv as createLocationValidator, cw as createMultiRelationValidator, cx as createMultiselectValidator, cy as createNumberValidator, cz as createObjectValidator, cA as createPhoneValidator, cB as createRatingValidator, cC as createRelationValidator, cD as createRichtextValidator, cE as createRollupValidator, cF as createSelectValidator, cG as createSingleRelationValidator, cI as createStatusValidator, cJ as createTextAreaValidator, cK as createTextValidator, cL as createUserValidator, cM as currencyConfigSchema, cN as dateConfigSchema, cO as documentConfigSchema, cQ as fileConfigSchema, cR as formatZodErrors, cS as formulaConfigSchema, cU as getAttributeConfigSchema, cW as getMissingRequiredAttributes, dt as isRecordComplete, dG as locationConfigSchema, dI as multiselectConfigSchema, dK as numberConfigSchema, dM as parseAttributeConfig, dN as phoneConfigSchema, dO as ratingConfigSchema, dP as relationConfigSchema, dQ as richtextConfigSchema, dR as rollupConfigSchema, dS as safeParseAttributeConfig, dT as selectConfigSchema, dV as statusConfigSchema, dW as textConfigSchema, dX as textareaConfigSchema, dY as userConfigSchema, dZ as validateAttribute, d_ as validateAttributeConfig, d$ as validateDraft, e0 as validateDraftOrThrow, e1 as validateObject, e2 as validateObjectOrThrow } from '../validators-BXWI__2n.js';
3
3
  import '@stndrds/constants';
4
4
  import '../utils.js';