@absolutejs/absolute 0.20.0-beta.14 → 0.20.0-beta.16

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/README.md CHANGED
@@ -189,6 +189,13 @@ owns persisted data declares its JSON-safe evolution in `package.json`:
189
189
  Absolute derives stable component IDs from package names, keeps independent
190
190
  version ledgers, validates migration gaps during build/doctor, and applies the
191
191
  same transaction atomically in IndexedDB or Capacitor SQLite before Sync starts.
192
+ The same `localSchema` object can declare `localData` rules for sensitivity,
193
+ encryption, memory-only fallback, whole-cache retention, eviction priority, and
194
+ per-principal quota. Absolute mobile stores record payloads as AES-256-GCM
195
+ ciphertext using a random key held by Keychain/Keystore; native background Sync
196
+ uses the identical authenticated format. Browsers without an audited key
197
+ provider either keep a declared fallback in memory only or fail closed. Pending
198
+ mutations are never evicted to satisfy quota.
192
199
 
193
200
  App updates are consent-driven: `onUpdateAvailable()` latches a waiting worker
194
201
  for late UI subscribers, `checkForUpdate()` performs a passive check, and
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-TLzq3x/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-TLzq3x/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-TLzq3x/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
package/dist/build.js CHANGED
@@ -12860,11 +12860,34 @@ var isTestSourcePath = (file) => {
12860
12860
  };
12861
12861
 
12862
12862
  // node_modules/@absolutejs/sync/dist/client/index.js
12863
- var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")), registry, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
12863
+ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")), registry, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
12864
12864
  if (!Number.isSafeInteger(value) || value < 1)
12865
12865
  throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
12866
12866
  return value;
12867
- }, isSchemaBundle = (schema) => ("components" in schema), normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
12867
+ }, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
12868
+ if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
12869
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
12870
+ }, validateSyncLocalDataPolicy = (policy, label = "localData") => {
12871
+ if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
12872
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
12873
+ for (const [index, rule] of (policy.collections ?? []).entries()) {
12874
+ validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
12875
+ if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
12876
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
12877
+ if (rule.persistence === "memory-only" && rule.protection === "required")
12878
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
12879
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
12880
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
12881
+ }
12882
+ for (const [index, rule] of (policy.mutations ?? []).entries()) {
12883
+ validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
12884
+ if (rule.persistence === "memory-only" && rule.protection === "required")
12885
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] cannot require at-rest protection when it is memory-only.`);
12886
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
12887
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
12888
+ }
12889
+ return policy;
12890
+ }, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
12868
12891
  const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
12869
12892
  const ids = new Set;
12870
12893
  for (const component of components) {
@@ -12873,6 +12896,8 @@ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" &
12873
12896
  if (ids.has(component.id))
12874
12897
  throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
12875
12898
  ids.add(component.id);
12899
+ if (component.localData)
12900
+ validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
12876
12901
  }
12877
12902
  return components.sort((a, b2) => a.id.localeCompare(b2.id));
12878
12903
  }, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
@@ -12930,6 +12955,14 @@ var init_client = __esm(() => {
12930
12955
  });
12931
12956
  return created;
12932
12957
  })();
12958
+ SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
12959
+ code;
12960
+ constructor(code, message) {
12961
+ super(message);
12962
+ this.name = "SyncLocalDataPolicyError";
12963
+ this.code = code;
12964
+ }
12965
+ };
12933
12966
  SyncLocalStoreSchemaError = class SyncLocalStoreSchemaError extends Error {
12934
12967
  code;
12935
12968
  storedVersion;
@@ -12986,7 +13019,7 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
12986
13019
  if (!object(value))
12987
13020
  throw metadataError(id, detail);
12988
13021
  return value;
12989
- }, normalizeJsonValue = (value, id, field) => {
13022
+ }, unknownField = (record, key) => record[key], normalizeJsonValue = (value, id, field) => {
12990
13023
  if (value === null || typeof value === "string" || typeof value === "boolean")
12991
13024
  return value;
12992
13025
  if (typeof value === "number" && Number.isFinite(value))
@@ -13037,9 +13070,113 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
13037
13070
  operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
13038
13071
  toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
13039
13072
  };
13073
+ }, localDataPolicy = (value, id) => {
13074
+ const record = requireObject(value, id, "localData must be an object.");
13075
+ const allowed = new Set([
13076
+ "collections",
13077
+ "maxBytesPerNamespace",
13078
+ "mutations"
13079
+ ]);
13080
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
13081
+ if (unsupported)
13082
+ throw metadataError(id, `localData.${unsupported} is not supported.`);
13083
+ const collectionRules = Reflect.get(record, "collections");
13084
+ const mutationRules = Reflect.get(record, "mutations");
13085
+ if (collectionRules !== undefined && !Array.isArray(collectionRules))
13086
+ throw metadataError(id, "localData.collections must be an array.");
13087
+ if (mutationRules !== undefined && !Array.isArray(mutationRules))
13088
+ throw metadataError(id, "localData.mutations must be an array.");
13089
+ const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
13090
+ const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
13091
+ const allowedRuleKeys = new Set([
13092
+ "evictionPriority",
13093
+ "match",
13094
+ "maxAgeMs",
13095
+ "onProtectionUnavailable",
13096
+ "persistence",
13097
+ "protection",
13098
+ "sensitivity"
13099
+ ]);
13100
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
13101
+ if (unsupportedRuleKey)
13102
+ throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
13103
+ const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
13104
+ const persistence = unknownField(rule, "persistence");
13105
+ const sensitivity = unknownField(rule, "sensitivity");
13106
+ const protection = unknownField(rule, "protection");
13107
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
13108
+ const evictionPriority = unknownField(rule, "evictionPriority");
13109
+ const maxAge = unknownField(rule, "maxAgeMs");
13110
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
13111
+ throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
13112
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
13113
+ throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
13114
+ if (protection !== undefined && protection !== "none" && protection !== "required")
13115
+ throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
13116
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
13117
+ throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
13118
+ if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
13119
+ throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
13120
+ return {
13121
+ match,
13122
+ ...sensitivity ? { sensitivity } : {},
13123
+ ...persistence ? { persistence } : {},
13124
+ ...protection ? { protection } : {},
13125
+ ...onProtectionUnavailable ? {
13126
+ onProtectionUnavailable
13127
+ } : {},
13128
+ ...evictionPriority ? { evictionPriority } : {},
13129
+ ...maxAge === undefined ? {} : {
13130
+ maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
13131
+ }
13132
+ };
13133
+ }) : undefined;
13134
+ const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
13135
+ const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
13136
+ const allowedRuleKeys = new Set([
13137
+ "match",
13138
+ "onProtectionUnavailable",
13139
+ "persistence",
13140
+ "protection",
13141
+ "sensitivity"
13142
+ ]);
13143
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
13144
+ if (unsupportedRuleKey)
13145
+ throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
13146
+ const protection = unknownField(rule, "protection");
13147
+ const sensitivity = unknownField(rule, "sensitivity");
13148
+ const persistence = unknownField(rule, "persistence");
13149
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
13150
+ if (protection !== undefined && protection !== "none" && protection !== "required")
13151
+ throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
13152
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
13153
+ throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
13154
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
13155
+ throw metadataError(id, `localData.mutations[${index}].onProtectionUnavailable is invalid.`);
13156
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
13157
+ throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
13158
+ return {
13159
+ match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
13160
+ ...sensitivity ? { sensitivity } : {},
13161
+ ...onProtectionUnavailable ? { onProtectionUnavailable } : {},
13162
+ ...persistence ? {
13163
+ persistence
13164
+ } : {},
13165
+ ...protection ? { protection } : {}
13166
+ };
13167
+ }) : undefined;
13168
+ const quota = Reflect.get(record, "maxBytesPerNamespace");
13169
+ return {
13170
+ ...collections ? { collections } : {},
13171
+ ...mutations ? { mutations } : {},
13172
+ ...quota === undefined ? {} : {
13173
+ maxBytesPerNamespace: positiveVersion2(quota, id, "localData.maxBytesPerNamespace")
13174
+ }
13175
+ };
13040
13176
  }, component = (id, value) => {
13041
13177
  const record = requireObject(value, id, "localSchema must be an object.");
13042
13178
  const allowed = new Set([
13179
+ "localData",
13043
13180
  "migrations",
13044
13181
  "minimumCompatibleVersion",
13045
13182
  "version"
@@ -13051,11 +13188,13 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
13051
13188
  const declaredMinimum = Reflect.get(record, "minimumCompatibleVersion");
13052
13189
  const minimumCompatibleVersion = declaredMinimum === undefined ? Math.max(1, version - 2) : positiveVersion2(declaredMinimum, id, "minimumCompatibleVersion");
13053
13190
  const declaredMigrations = Reflect.get(record, "migrations");
13191
+ const declaredLocalData = Reflect.get(record, "localData");
13054
13192
  if (declaredMigrations !== undefined && !Array.isArray(declaredMigrations))
13055
13193
  throw metadataError(id, "migrations must be an array.");
13056
13194
  const migrations = Array.isArray(declaredMigrations) ? declaredMigrations : undefined;
13057
13195
  return {
13058
13196
  id,
13197
+ ...declaredLocalData === undefined ? {} : { localData: localDataPolicy(declaredLocalData, id) },
13059
13198
  minimumCompatibleVersion,
13060
13199
  ...Array.isArray(migrations) ? {
13061
13200
  migrations: migrations.map((entry, index) => migration(entry, id, index))
@@ -29883,5 +30022,5 @@ export {
29883
30022
  build
29884
30023
  };
29885
30024
 
29886
- //# debugId=452381297EE1F66D64756E2164756E21
30025
+ //# debugId=8331CE4644B33A6A64756E2164756E21
29887
30026
  //# sourceMappingURL=build.js.map