@absolutejs/absolute 0.20.0-beta.179 → 0.20.0-beta.180

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 (125) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/changelog.json +45 -0
  3. package/dist/angular/browser.js +2 -2
  4. package/dist/angular/browser.js.map +3 -3
  5. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  6. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  7. package/dist/angular/index.js +21 -6
  8. package/dist/angular/index.js.map +6 -6
  9. package/dist/angular/server.js +21 -6
  10. package/dist/angular/server.js.map +6 -6
  11. package/dist/build.js +5357 -4945
  12. package/dist/build.js.map +27 -24
  13. package/dist/cli/build-fntmf42w.js +495 -0
  14. package/dist/cli/{buildDepVendor-qvsh6dsj.js → buildDepVendor-qnwfct22.js} +5 -3
  15. package/dist/cli/buildReactServerComponents-fq6mw10d.js +13 -0
  16. package/dist/cli/{compile-p5yv6ecp.js → compile-54rb8szn.js} +94 -125
  17. package/dist/cli/config/server.js +10 -5
  18. package/dist/cli/{dev-2hbcsvkp.js → dev-6s6g5tnk.js} +13 -14
  19. package/dist/cli/{expoProject-1qtw97js.js → expoProject-acgfaj3f.js} +2 -1
  20. package/dist/cli/generatedDir-239r7csr.js +9 -0
  21. package/dist/cli/{index-cksezef8.js → index-0gd30trc.js} +105 -851
  22. package/dist/cli/index-2wvysvjc.js +40 -0
  23. package/dist/cli/index-42xjh6gg.js +282 -0
  24. package/dist/cli/{index-qw98g1p6.js → index-47e8fwha.js} +4 -1
  25. package/dist/cli/index-65kqn88a.js +8 -0
  26. package/dist/cli/{index-2bxfhs32.js → index-6f448d7m.js} +0 -26
  27. package/dist/cli/index-972xxwgj.js +16 -0
  28. package/dist/cli/index-aqe25w4h.js +39 -0
  29. package/dist/cli/index-assqancr.js +51 -0
  30. package/dist/cli/{index-2shf4aya.js → index-c8rcfe5a.js} +4 -6
  31. package/dist/cli/index-cba1cemz.js +8 -0
  32. package/dist/cli/{index-3ff5ztt3.js → index-djkrb7pc.js} +1 -7
  33. package/dist/cli/index-dkfwkpc8.js +138 -0
  34. package/dist/cli/{index-92g14j47.js → index-dw44xa4x.js} +2 -1
  35. package/dist/cli/index-evsnq0n2.js +17 -0
  36. package/dist/cli/index-fxwf3n2v.js +224 -0
  37. package/dist/cli/{index-zyd80s3h.js → index-js2hksgv.js} +21 -295
  38. package/dist/cli/{index-bp60baze.js → index-jyap0bhv.js} +1 -1
  39. package/dist/cli/{index-9dzdbbfc.js → index-kx2d067c.js} +8 -6
  40. package/dist/cli/index-pb31zan6.js +9 -0
  41. package/dist/cli/index-sq0478b0.js +281 -0
  42. package/dist/cli/index-va274tsf.js +7 -0
  43. package/dist/cli/{index-yd672jyq.js → index-w6xsk8cv.js} +4 -1
  44. package/dist/cli/index-w79snsxv.js +461 -0
  45. package/dist/cli/index-x1vvn549.js +835 -0
  46. package/dist/cli/index-xf9sfr8a.js +243 -0
  47. package/dist/cli/index-ycqdxy55.js +754 -0
  48. package/dist/cli/index-z74cqxz0.js +131 -0
  49. package/dist/cli/index.js +10 -9
  50. package/dist/cli/{islands-6zgb7501.js → islands-17tfx8jf.js} +6 -17
  51. package/dist/cli/{ls-0hfx323m.js → ls-0wr74w0b.js} +10 -58
  52. package/dist/cli/{mobile-93vaawcz.js → mobile-hpqpy61f.js} +11 -8
  53. package/dist/cli/{prerender-010z771p.js → prerender-w65xp6h8.js} +2 -1
  54. package/dist/cli/{rewriteImports-z6629aww.js → rewriteImports-np2d2kvc.js} +4 -11
  55. package/dist/cli/rewriteImportsPlugin-c6hcb3x6.js +12 -0
  56. package/dist/cli/{start-asxb79rc.js → start-mbn2zgs2.js} +6 -4
  57. package/dist/cli/staticAnalyzeSpaRoutes-2nev05m1.js +8 -0
  58. package/dist/cli/staticAnalyzeSpaRoutes-6vgzp0rs.js +8 -0
  59. package/dist/cli/staticAnalyzeSpaRoutes-f85q9dqk.js +8 -0
  60. package/dist/cli/staticAnalyzeSpaRoutes-yakmg22g.js +7 -0
  61. package/dist/cli/{typecheck-m2j4tkdk.js → typecheck-488txsfc.js} +92 -18
  62. package/dist/cli/vueCompiler-8bzdmf08.js +7 -0
  63. package/dist/client/chunks/{react-khr6ewhr.js → react-g8r290b8.js} +37 -2
  64. package/dist/client/chunks/react-g8r290b8.js.map +10 -0
  65. package/dist/client/chunks/vue-zcpmka32.js +85 -0
  66. package/dist/client/chunks/vue-zcpmka32.js.map +10 -0
  67. package/dist/client/index.js +58 -10
  68. package/dist/client/index.js.map +4 -4
  69. package/dist/dev/client/handlers/vue.ts +116 -0
  70. package/dist/index.js +2472 -2058
  71. package/dist/index.js.map +26 -23
  72. package/dist/islands/browser.js +2 -2
  73. package/dist/islands/browser.js.map +3 -3
  74. package/dist/islands/index.js +2 -2
  75. package/dist/islands/index.js.map +3 -3
  76. package/dist/react/browser.js +2 -2
  77. package/dist/react/browser.js.map +3 -3
  78. package/dist/react/index.js +42 -11
  79. package/dist/react/index.js.map +10 -10
  80. package/dist/react/server.js +42 -11
  81. package/dist/react/server.js.map +10 -10
  82. package/dist/src/angular/ssrRender.d.ts +2 -2
  83. package/dist/src/angular/staticAnalyzeSpaRoutes.d.ts +6 -1
  84. package/dist/src/build/generateManifest.d.ts +15 -0
  85. package/dist/src/build/manifestKeys.d.ts +22 -0
  86. package/dist/src/cli/add/dependencies.d.ts +1 -1
  87. package/dist/src/cli/scripts/typecheck.d.ts +11 -0
  88. package/dist/src/client/hydrators/react.d.ts +10 -0
  89. package/dist/src/client/hydrators/vue.d.ts +13 -0
  90. package/dist/src/client/islandRuntime.d.ts +1 -1
  91. package/dist/src/core/islandManifest.d.ts +4 -0
  92. package/dist/src/core/islandPageContext.d.ts +8 -2
  93. package/dist/src/core/lookup.d.ts +16 -1
  94. package/dist/src/dev/importCost/instrument.d.ts +1 -1
  95. package/dist/src/dev/manifestKeysRefresher.d.ts +6 -0
  96. package/dist/src/dev/spaRouteRefresh.d.ts +13 -0
  97. package/dist/src/mobile/androidConformance.d.ts +1 -1
  98. package/dist/src/react/staticAnalyzeSpaRoutes.d.ts +6 -1
  99. package/dist/src/svelte/staticAnalyzeSpaRoutes.d.ts +1 -0
  100. package/dist/src/utils/logger.d.ts +5 -0
  101. package/dist/src/utils/spaRouteManifest.d.ts +1 -0
  102. package/dist/src/vue/components/Image.d.ts +4 -4
  103. package/dist/src/vue/components/StreamSlot.d.ts +1 -1
  104. package/dist/src/vue/components/SuspenseSlot.d.ts +2 -2
  105. package/dist/src/vue/staticAnalyzeSpaRoutes.d.ts +4 -0
  106. package/dist/svelte/browser.js +2 -2
  107. package/dist/svelte/browser.js.map +3 -3
  108. package/dist/svelte/index.js +25 -9
  109. package/dist/svelte/index.js.map +8 -8
  110. package/dist/svelte/server.js +25 -9
  111. package/dist/svelte/server.js.map +8 -8
  112. package/dist/types/globals.d.ts +4 -0
  113. package/dist/types/index.d.ts +1 -0
  114. package/dist/types/island.d.ts +1 -1
  115. package/dist/types/manifest.d.ts +25 -0
  116. package/dist/vue/browser.js +2 -2
  117. package/dist/vue/browser.js.map +3 -3
  118. package/dist/vue/index.js +21 -6
  119. package/dist/vue/index.js.map +6 -6
  120. package/dist/vue/server.js +21 -6
  121. package/dist/vue/server.js.map +6 -6
  122. package/package.json +1 -1
  123. package/dist/client/chunks/react-khr6ewhr.js.map +0 -10
  124. package/dist/client/chunks/vue-db6ppn1f.js +0 -32
  125. package/dist/client/chunks/vue-db6ppn1f.js.map +0 -10
@@ -0,0 +1,754 @@
1
+ // @bun
2
+ import {
3
+ lazyTypescript
4
+ } from "./index-4j1twret.js";
5
+
6
+ // src/mobile/syncSchema.ts
7
+ import { readFileSync } from "fs";
8
+ import { dirname, join, resolve } from "path";
9
+
10
+ // node_modules/@absolutejs/sync/dist/client/index.js
11
+ var pools = new Map;
12
+ class SyncLocalDataPolicyError extends Error {
13
+ code;
14
+ constructor(code, message) {
15
+ super(message);
16
+ this.name = "SyncLocalDataPolicyError";
17
+ this.code = code;
18
+ }
19
+ }
20
+
21
+ class SyncLocalStoreSchemaError extends Error {
22
+ code;
23
+ storedVersion;
24
+ targetVersion;
25
+ constructor(code, message, versions = {}) {
26
+ super(message);
27
+ this.name = "SyncLocalStoreSchemaError";
28
+ this.code = code;
29
+ this.storedVersion = versions.storedVersion;
30
+ this.targetVersion = versions.targetVersion;
31
+ }
32
+ }
33
+ var positiveVersion = (value, label) => {
34
+ if (!Number.isSafeInteger(value) || value < 1)
35
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
36
+ return value;
37
+ };
38
+ var isSchemaBundle = (schema) => ("components" in schema);
39
+ var validatePolicyMatch = (match, label) => {
40
+ if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
41
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
42
+ };
43
+ var validateSyncLocalDataPolicy = (policy, label = "localData") => {
44
+ if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
45
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
46
+ for (const [index, rule] of (policy.collections ?? []).entries()) {
47
+ validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
48
+ if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
49
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
50
+ if (rule.persistence === "memory-only" && rule.protection === "required")
51
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
52
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
53
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
54
+ }
55
+ for (const [index, rule] of (policy.mutations ?? []).entries()) {
56
+ validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
57
+ if (rule.conflict !== undefined && rule.conflict.strategy !== "client-wins" && rule.conflict.strategy !== "manual" && rule.conflict.strategy !== "server-wins")
58
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.strategy is invalid.`);
59
+ if (rule.conflict?.maxAttempts !== undefined && (!Number.isSafeInteger(rule.conflict.maxAttempts) || rule.conflict.maxAttempts < 1))
60
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts must be a positive safe integer.`);
61
+ if (rule.conflict?.maxAttempts !== undefined && rule.conflict.strategy !== "client-wins")
62
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts is only valid for client-wins.`);
63
+ if (rule.persistence === "memory-only" && rule.protection === "required")
64
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] cannot require at-rest protection when it is memory-only.`);
65
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
66
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
67
+ }
68
+ return policy;
69
+ };
70
+ var normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
71
+ const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
72
+ const ids = new Set;
73
+ for (const component of components) {
74
+ if (typeof component.id !== "string" || component.id.trim() !== component.id || component.id.length === 0)
75
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Sync schema component id must be non-empty and trimmed");
76
+ if (ids.has(component.id))
77
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
78
+ ids.add(component.id);
79
+ if (component.localData)
80
+ validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
81
+ }
82
+ return components.sort((a, b) => a.id.localeCompare(b.id));
83
+ };
84
+ var resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
85
+ const components = normalizeSyncLocalSchemaComponents(schema).map((component) => {
86
+ const current = resolveSyncLocalMigrations(component.version, component);
87
+ return {
88
+ id: component.id,
89
+ ...resolveSyncLocalMigrations(storedVersions[component.id] ?? current.minimumCompatibleVersion, component)
90
+ };
91
+ });
92
+ const active = new Set(components.map((component) => component.id));
93
+ const orphanedComponents = Object.keys(storedVersions).filter((id) => !active.has(id)).sort();
94
+ return { components, orphanedComponents };
95
+ };
96
+ var resolveSyncLocalMigrations = (storedVersion, schema = { version: 1 }) => {
97
+ positiveVersion(storedVersion, "Stored Sync schema version");
98
+ const targetVersion = positiveVersion(schema.version, "Target Sync schema version");
99
+ const migrations = [...schema.migrations ?? []].sort((a, b) => a.toVersion - b.toVersion);
100
+ const versions = new Set;
101
+ for (const migration of migrations) {
102
+ positiveVersion(migration.toVersion, "Sync migration toVersion");
103
+ if (versions.has(migration.toVersion))
104
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync migration ${migration.toVersion} is declared more than once`);
105
+ versions.add(migration.toVersion);
106
+ }
107
+ const inferredMinimum = migrations[0] ? migrations[0].toVersion - 1 : targetVersion;
108
+ const minimumCompatibleVersion = positiveVersion(schema.minimumCompatibleVersion ?? inferredMinimum, "Minimum compatible Sync schema version");
109
+ if (minimumCompatibleVersion > targetVersion)
110
+ throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Minimum compatible Sync schema version cannot exceed its target");
111
+ if (storedVersion > targetVersion)
112
+ throw new SyncLocalStoreSchemaError("SCHEMA_TOO_NEW", `Stored Sync schema ${storedVersion} is newer than this runtime's schema ${targetVersion}`, { storedVersion, targetVersion });
113
+ if (storedVersion < minimumCompatibleVersion)
114
+ throw new SyncLocalStoreSchemaError("SCHEMA_TOO_OLD", `Stored Sync schema ${storedVersion} is older than the minimum compatible schema ${minimumCompatibleVersion}`, { storedVersion, targetVersion });
115
+ const steps = [];
116
+ for (let version = storedVersion + 1;version <= targetVersion; version++) {
117
+ const migration = migrations.find((candidate) => candidate.toVersion === version);
118
+ if (migration === undefined)
119
+ throw new SyncLocalStoreSchemaError("MIGRATION_MISSING", `Sync migration ${version - 1} -> ${version} is missing`, { storedVersion, targetVersion });
120
+ steps.push(migration);
121
+ }
122
+ return { minimumCompatibleVersion, steps, targetVersion };
123
+ };
124
+ var RUNTIME_TRANSPORT = Symbol.for("@absolutejs/sync/client-runtime-transport");
125
+ var host = globalThis;
126
+ var isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")) && Array.isArray(Reflect.get(value, "clients"));
127
+ var registry = (() => {
128
+ const existing = host[RUNTIME_TRANSPORT];
129
+ if (isRegistry(existing))
130
+ return existing;
131
+ if (typeof existing === "object" && existing !== null && Array.isArray(Reflect.get(existing, "installations"))) {
132
+ Reflect.set(existing, "clients", []);
133
+ return existing;
134
+ }
135
+ const created = { clients: [], installations: [] };
136
+ Object.defineProperty(host, RUNTIME_TRANSPORT, {
137
+ configurable: false,
138
+ enumerable: false,
139
+ value: created,
140
+ writable: false
141
+ });
142
+ return created;
143
+ })();
144
+
145
+ // src/mobile/syncSchema.ts
146
+ var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
147
+ var manifestAt = (path) => {
148
+ try {
149
+ const value = JSON.parse(readFileSync(path, "utf8"));
150
+ return object(value) ? value : undefined;
151
+ } catch {
152
+ return;
153
+ }
154
+ };
155
+ var localSchemaMetadata = (manifest) => {
156
+ const absolutejs = Reflect.get(manifest, "absolutejs");
157
+ if (!object(absolutejs))
158
+ return;
159
+ const sync = Reflect.get(absolutejs, "sync");
160
+ if (!object(sync))
161
+ return;
162
+ return Reflect.get(sync, "localSchema");
163
+ };
164
+ var packageManifestPath = (projectRoot, packageName) => {
165
+ let directory = resolve(projectRoot);
166
+ while (true) {
167
+ const candidate = join(directory, "node_modules", packageName, "package.json");
168
+ const manifest = manifestAt(candidate);
169
+ if (manifest && Reflect.get(manifest, "name") === packageName)
170
+ return candidate;
171
+ const parent = dirname(directory);
172
+ if (parent === directory)
173
+ return;
174
+ directory = parent;
175
+ }
176
+ };
177
+ var metadataError = (id, detail) => new TypeError(`Invalid AbsoluteJS Sync schema metadata for ${id}: ${detail}`);
178
+ var positiveVersion2 = (value, id, field) => {
179
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
180
+ throw metadataError(id, `${field} must be a positive safe integer.`);
181
+ return value;
182
+ };
183
+ var nonEmpty = (value, id, field) => {
184
+ if (typeof value !== "string" || value.trim() !== value || value.length === 0)
185
+ throw metadataError(id, `${field} must be a non-empty trimmed string.`);
186
+ return value;
187
+ };
188
+ var requireObject = (value, id, detail) => {
189
+ if (!object(value))
190
+ throw metadataError(id, detail);
191
+ return value;
192
+ };
193
+ var unknownField = (record, key) => record[key];
194
+ var normalizeJsonValue = (value, id, field) => {
195
+ if (value === null || typeof value === "string" || typeof value === "boolean")
196
+ return value;
197
+ if (typeof value === "number" && Number.isFinite(value))
198
+ return value;
199
+ if (Array.isArray(value))
200
+ return value.map((entry) => normalizeJsonValue(entry, id, field));
201
+ if (object(value))
202
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
203
+ key,
204
+ normalizeJsonValue(entry, id, field)
205
+ ]));
206
+ throw metadataError(id, `${field} must be JSON-safe.`);
207
+ };
208
+ var operation = (value, id, index) => {
209
+ const record = requireObject(value, id, `migration operation ${index} must be an object.`);
210
+ const type = Reflect.get(record, "type");
211
+ const collection = nonEmpty(Reflect.get(record, "collection"), id, `operation ${index}.collection`);
212
+ if (type === "delete-collection")
213
+ return { collection, type };
214
+ if (type === "rename-field")
215
+ return {
216
+ collection,
217
+ from: nonEmpty(Reflect.get(record, "from"), id, `operation ${index}.from`),
218
+ to: nonEmpty(Reflect.get(record, "to"), id, `operation ${index}.to`),
219
+ type
220
+ };
221
+ const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
222
+ if (type === "remove-field")
223
+ return { collection, field, type };
224
+ if (type === "set-default")
225
+ return {
226
+ collection,
227
+ field,
228
+ type,
229
+ value: normalizeJsonValue(Reflect.get(record, "value"), id, `operation ${index}.value`)
230
+ };
231
+ throw metadataError(id, `operation ${index}.type is not supported.`);
232
+ };
233
+ var migration = (value, id, index) => {
234
+ const record = requireObject(value, id, `migration ${index} must be an object.`);
235
+ const allowed = new Set(["operations", "toVersion"]);
236
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
237
+ if (unsupported)
238
+ throw metadataError(id, `migration ${index}.${unsupported} is not declarative metadata.`);
239
+ const declaredOperations = Reflect.get(record, "operations");
240
+ if (declaredOperations !== undefined && !Array.isArray(declaredOperations))
241
+ throw metadataError(id, `migration ${index}.operations must be an array.`);
242
+ const operations = Array.isArray(declaredOperations) ? declaredOperations : [];
243
+ return {
244
+ operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
245
+ toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
246
+ };
247
+ };
248
+ var localDataPolicy = (value, id) => {
249
+ const record = requireObject(value, id, "localData must be an object.");
250
+ const allowed = new Set([
251
+ "collections",
252
+ "maxBytesPerNamespace",
253
+ "mutations"
254
+ ]);
255
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
256
+ if (unsupported)
257
+ throw metadataError(id, `localData.${unsupported} is not supported.`);
258
+ const collectionRules = Reflect.get(record, "collections");
259
+ const mutationRules = Reflect.get(record, "mutations");
260
+ if (collectionRules !== undefined && !Array.isArray(collectionRules))
261
+ throw metadataError(id, "localData.collections must be an array.");
262
+ if (mutationRules !== undefined && !Array.isArray(mutationRules))
263
+ throw metadataError(id, "localData.mutations must be an array.");
264
+ const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
265
+ const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
266
+ const allowedRuleKeys = new Set([
267
+ "evictionPriority",
268
+ "match",
269
+ "maxAgeMs",
270
+ "onProtectionUnavailable",
271
+ "persistence",
272
+ "protection",
273
+ "sensitivity"
274
+ ]);
275
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
276
+ if (unsupportedRuleKey)
277
+ throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
278
+ const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
279
+ const persistence = unknownField(rule, "persistence");
280
+ const sensitivity = unknownField(rule, "sensitivity");
281
+ const protection = unknownField(rule, "protection");
282
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
283
+ const evictionPriority = unknownField(rule, "evictionPriority");
284
+ const maxAge = unknownField(rule, "maxAgeMs");
285
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
286
+ throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
287
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
288
+ throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
289
+ if (protection !== undefined && protection !== "none" && protection !== "required")
290
+ throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
291
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
292
+ throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
293
+ if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
294
+ throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
295
+ return {
296
+ match,
297
+ ...sensitivity ? { sensitivity } : {},
298
+ ...persistence ? { persistence } : {},
299
+ ...protection ? { protection } : {},
300
+ ...onProtectionUnavailable ? {
301
+ onProtectionUnavailable
302
+ } : {},
303
+ ...evictionPriority ? { evictionPriority } : {},
304
+ ...maxAge === undefined ? {} : {
305
+ maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
306
+ }
307
+ };
308
+ }) : undefined;
309
+ const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
310
+ const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
311
+ const allowedRuleKeys = new Set([
312
+ "conflict",
313
+ "match",
314
+ "onProtectionUnavailable",
315
+ "persistence",
316
+ "protection",
317
+ "sensitivity"
318
+ ]);
319
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
320
+ if (unsupportedRuleKey)
321
+ throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
322
+ const protection = unknownField(rule, "protection");
323
+ const sensitivity = unknownField(rule, "sensitivity");
324
+ const persistence = unknownField(rule, "persistence");
325
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
326
+ const declaredConflict = unknownField(rule, "conflict");
327
+ let conflict;
328
+ if (declaredConflict !== undefined) {
329
+ const conflictRecord = requireObject(declaredConflict, id, `localData.mutations[${index}].conflict must be an object.`);
330
+ const unsupportedConflictKey = Object.keys(conflictRecord).find((key) => key !== "maxAttempts" && key !== "strategy");
331
+ if (unsupportedConflictKey)
332
+ throw metadataError(id, `localData.mutations[${index}].conflict.${unsupportedConflictKey} is not supported.`);
333
+ const strategy = unknownField(conflictRecord, "strategy");
334
+ if (strategy !== "client-wins" && strategy !== "manual" && strategy !== "server-wins")
335
+ throw metadataError(id, `localData.mutations[${index}].conflict.strategy is invalid.`);
336
+ const maxAttempts = unknownField(conflictRecord, "maxAttempts");
337
+ if (maxAttempts !== undefined && strategy !== "client-wins")
338
+ throw metadataError(id, `localData.mutations[${index}].conflict.maxAttempts requires client-wins.`);
339
+ conflict = {
340
+ strategy,
341
+ ...maxAttempts === undefined ? {} : {
342
+ maxAttempts: positiveVersion2(maxAttempts, id, `localData.mutations[${index}].conflict.maxAttempts`)
343
+ }
344
+ };
345
+ }
346
+ if (protection !== undefined && protection !== "none" && protection !== "required")
347
+ throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
348
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
349
+ throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
350
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
351
+ throw metadataError(id, `localData.mutations[${index}].onProtectionUnavailable is invalid.`);
352
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
353
+ throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
354
+ return {
355
+ match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
356
+ ...conflict ? { conflict } : {},
357
+ ...sensitivity ? { sensitivity } : {},
358
+ ...onProtectionUnavailable ? { onProtectionUnavailable } : {},
359
+ ...persistence ? {
360
+ persistence
361
+ } : {},
362
+ ...protection ? { protection } : {}
363
+ };
364
+ }) : undefined;
365
+ const quota = Reflect.get(record, "maxBytesPerNamespace");
366
+ return {
367
+ ...collections ? { collections } : {},
368
+ ...mutations ? { mutations } : {},
369
+ ...quota === undefined ? {} : {
370
+ maxBytesPerNamespace: positiveVersion2(quota, id, "localData.maxBytesPerNamespace")
371
+ }
372
+ };
373
+ };
374
+ var component = (id, value) => {
375
+ const record = requireObject(value, id, "localSchema must be an object.");
376
+ const allowed = new Set([
377
+ "localData",
378
+ "migrations",
379
+ "minimumCompatibleVersion",
380
+ "version"
381
+ ]);
382
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
383
+ if (unsupported)
384
+ throw metadataError(id, `${unsupported} is not supported.`);
385
+ const version = positiveVersion2(Reflect.get(record, "version"), id, "version");
386
+ const declaredMinimum = Reflect.get(record, "minimumCompatibleVersion");
387
+ const minimumCompatibleVersion = declaredMinimum === undefined ? Math.max(1, version - 2) : positiveVersion2(declaredMinimum, id, "minimumCompatibleVersion");
388
+ const declaredMigrations = Reflect.get(record, "migrations");
389
+ const declaredLocalData = Reflect.get(record, "localData");
390
+ if (declaredMigrations !== undefined && !Array.isArray(declaredMigrations))
391
+ throw metadataError(id, "migrations must be an array.");
392
+ const migrations = Array.isArray(declaredMigrations) ? declaredMigrations : undefined;
393
+ return {
394
+ id,
395
+ ...declaredLocalData === undefined ? {} : { localData: localDataPolicy(declaredLocalData, id) },
396
+ minimumCompatibleVersion,
397
+ ...Array.isArray(migrations) ? {
398
+ migrations: migrations.map((entry, index) => migration(entry, id, index))
399
+ } : {},
400
+ version
401
+ };
402
+ };
403
+ var dependencyNames = (manifest) => [
404
+ Reflect.get(manifest, "dependencies"),
405
+ Reflect.get(manifest, "optionalDependencies"),
406
+ Reflect.get(manifest, "devDependencies"),
407
+ Reflect.get(manifest, "peerDependencies")
408
+ ].flatMap((dependencies) => object(dependencies) ? Object.keys(dependencies) : []).filter((name, index, names) => names.indexOf(name) === index).sort();
409
+ var discoverAbsoluteSyncSchema = (projectRoot) => {
410
+ const appManifestPath = join(resolve(projectRoot), "package.json");
411
+ const appManifest = manifestAt(appManifestPath);
412
+ if (!appManifest)
413
+ return {
414
+ components: [
415
+ {
416
+ id: "@absolutejs/app",
417
+ minimumCompatibleVersion: 1,
418
+ version: 1
419
+ }
420
+ ],
421
+ sources: []
422
+ };
423
+ const appMetadata = localSchemaMetadata(appManifest);
424
+ const components = [
425
+ appMetadata === undefined ? { id: "@absolutejs/app", minimumCompatibleVersion: 1, version: 1 } : component("@absolutejs/app", appMetadata)
426
+ ];
427
+ const sources = [
428
+ { id: "@absolutejs/app", manifestPath: appManifestPath }
429
+ ];
430
+ for (const name of dependencyNames(appManifest)) {
431
+ const manifestPath = packageManifestPath(projectRoot, name);
432
+ if (!manifestPath)
433
+ continue;
434
+ const manifest = manifestAt(manifestPath);
435
+ if (!manifest)
436
+ continue;
437
+ const metadata = localSchemaMetadata(manifest);
438
+ if (metadata === undefined)
439
+ continue;
440
+ components.push(component(name, metadata));
441
+ sources.push({ id: name, manifestPath });
442
+ }
443
+ components.sort((left, right) => left.id.localeCompare(right.id));
444
+ sources.sort((left, right) => left.id.localeCompare(right.id));
445
+ resolveSyncLocalSchemaComponents({}, { components });
446
+ return { components, sources };
447
+ };
448
+
449
+ // src/mobile/deviceCapabilities.ts
450
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
451
+ import { extname, join as join2, relative, resolve as resolve2 } from "path";
452
+ import { fileURLToPath } from "url";
453
+ var DEVICES_PACKAGE = "@absolutejs/devices";
454
+ var ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABILITIES = [
455
+ "keyboard",
456
+ "systemBars"
457
+ ];
458
+ var ADAPTERS = {
459
+ capacitor: "@absolutejs/devices-capacitor",
460
+ expo: "@absolutejs/devices-expo"
461
+ };
462
+ var SOURCE_GLOB = new Bun.Glob("**/*.{js,jsx,ts,tsx,svelte,vue}");
463
+ var IGNORED_DIRECTORIES = new Set([
464
+ ".absolutejs",
465
+ ".git",
466
+ ".test-builds",
467
+ ".test-shards",
468
+ "build",
469
+ "dist",
470
+ "node_modules",
471
+ "test",
472
+ "tests"
473
+ ]);
474
+ var IDENTIFIER_PATTERN = /^[A-Za-z_$][\w$]*$/u;
475
+ var providerModulePattern = (provider) => new RegExp(`^@absolutejs/devices-${provider}/[a-z][a-z0-9-]*$`, "u");
476
+ var providerPackagePattern = (provider) => provider === "capacitor" ? /^@capacitor\/[a-z][a-z0-9-]*@\d+\.\d+\.\d+$/u : /^(?:expo-[a-z][a-z0-9-]*|@react-native-[a-z0-9-]+\/[a-z][a-z0-9-]*)@\d+\.\d+\.\d+$/u;
477
+ var providerLabel = (provider) => provider === "capacitor" ? "Capacitor" : "Expo";
478
+ var ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
479
+ var IOS_USAGE_DESCRIPTIONS = new Set([
480
+ "camera",
481
+ "location-always",
482
+ "location-when-in-use",
483
+ "photo-library",
484
+ "photo-library-add"
485
+ ]);
486
+ var IOS_PRIVACY_ACCESSED_API_REASONS = {
487
+ NSPrivacyAccessedAPICategoryFileTimestamp: new Set(["C617.1"])
488
+ };
489
+ var IOS_PRIVACY_ACCESSED_APIS = [
490
+ "NSPrivacyAccessedAPICategoryFileTimestamp"
491
+ ];
492
+ var object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
493
+ var readJson = (path) => {
494
+ const value = JSON.parse(readFileSync2(path, "utf8"));
495
+ if (!object2(value))
496
+ throw new TypeError(`${path} must contain an object.`);
497
+ return value;
498
+ };
499
+ var text = (value, field) => {
500
+ if (typeof value !== "string" || value.length === 0)
501
+ throw new TypeError(`${field} must be a non-empty string.`);
502
+ return value;
503
+ };
504
+ var androidPermissions = (value, field) => {
505
+ if (value === undefined)
506
+ return;
507
+ if (!object2(value))
508
+ throw new TypeError(`${field} must be an object.`);
509
+ const { permissions } = value;
510
+ if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
511
+ throw new TypeError(`${field}.permissions must contain Android permission names.`);
512
+ return [...permissions];
513
+ };
514
+ var iosPrivacyAccessedApis = (value, field) => {
515
+ if (value === undefined)
516
+ return;
517
+ if (!object2(value))
518
+ throw new TypeError(`${field} must be an object.`);
519
+ const privacy = {};
520
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
521
+ const reasons = value[api];
522
+ if (reasons === undefined)
523
+ continue;
524
+ const supported = IOS_PRIVACY_ACCESSED_API_REASONS[api];
525
+ if (!Array.isArray(reasons) || reasons.length === 0 || !reasons.every((reason) => typeof reason === "string" && supported.has(reason)))
526
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
527
+ privacy[api] = [...reasons];
528
+ }
529
+ if (Object.keys(value).some((api) => !IOS_PRIVACY_ACCESSED_APIS.some((known) => known === api)))
530
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
531
+ return privacy;
532
+ };
533
+ var iosNativeRequirements = (value, field) => {
534
+ if (value === undefined)
535
+ return;
536
+ if (!object2(value))
537
+ throw new TypeError(`${field} must be an object.`);
538
+ const {
539
+ privacyAccessedApis,
540
+ pushNotifications,
541
+ systemBars,
542
+ usageDescriptions
543
+ } = value;
544
+ if (pushNotifications !== undefined && pushNotifications !== true)
545
+ throw new TypeError(`${field}.pushNotifications must be true.`);
546
+ if (systemBars !== undefined && systemBars !== true)
547
+ throw new TypeError(`${field}.systemBars must be true.`);
548
+ if (usageDescriptions !== undefined && (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose))))
549
+ throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
550
+ const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field}.privacyAccessedApis`);
551
+ return {
552
+ ...privacy === undefined ? {} : { privacyAccessedApis: privacy },
553
+ ...pushNotifications === true ? { pushNotifications: true } : {},
554
+ ...systemBars === true ? { systemBars: true } : {},
555
+ ...usageDescriptions === undefined ? {} : { usageDescriptions: [...usageDescriptions] }
556
+ };
557
+ };
558
+ var parseProvider = (name, value, providerName) => {
559
+ if (!IDENTIFIER_PATTERN.test(name))
560
+ throw new TypeError("Device capability names must be identifiers.");
561
+ if (!object2(value))
562
+ throw new TypeError(`Device capability ${name} must be an object.`);
563
+ const factory = text(value.factory, `${name}.factory`);
564
+ const module = text(value.module, `${name}.module`);
565
+ if (!IDENTIFIER_PATTERN.test(factory))
566
+ throw new TypeError(`${name}.factory must be a JavaScript identifier.`);
567
+ if (!providerModulePattern(providerName).test(module))
568
+ throw new TypeError(`${name}.module must be an official devices-${providerName} subpath.`);
569
+ if (!Array.isArray(value.packages) || !value.packages.every((spec) => typeof spec === "string" && providerPackagePattern(providerName).test(spec)))
570
+ throw new TypeError(`${name}.packages must contain exact official ${providerLabel(providerName)} package versions.`);
571
+ const { plugins } = value;
572
+ if (plugins !== undefined && (!Array.isArray(plugins) || !plugins.every((plugin) => typeof plugin === "string" && /^expo-[a-z][a-z0-9-]*$/u.test(plugin))))
573
+ throw new TypeError(`${name}.plugins must contain Expo config plugin names.`);
574
+ let native;
575
+ const { native: nativeMetadata } = value;
576
+ if (nativeMetadata !== undefined) {
577
+ if (!object2(nativeMetadata))
578
+ throw new TypeError(`${name}.native must be an object.`);
579
+ const { android, ios } = nativeMetadata;
580
+ const permissions = androidPermissions(android, `${name}.native.android`);
581
+ const iosRequirements = iosNativeRequirements(ios, `${name}.native.ios`);
582
+ native = {
583
+ ...permissions === undefined ? {} : { android: { permissions } },
584
+ ...iosRequirements === undefined ? {} : { ios: iosRequirements }
585
+ };
586
+ }
587
+ return {
588
+ factory,
589
+ module,
590
+ ...native === undefined ? {} : { native },
591
+ ...plugins === undefined ? {} : { plugins: [...plugins] },
592
+ packages: [...value.packages]
593
+ };
594
+ };
595
+ var absoluteDeviceNativeRequirements = (plan) => {
596
+ const privacy = plan.capabilities.reduce((requirements, name) => {
597
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
598
+ const reasons = plan.providers[name]?.native?.ios?.privacyAccessedApis?.[api] ?? [];
599
+ if (reasons.length === 0)
600
+ continue;
601
+ const current = requirements[api] ?? new Set;
602
+ for (const reason of reasons)
603
+ current.add(reason);
604
+ requirements[api] = current;
605
+ }
606
+ return requirements;
607
+ }, {});
608
+ return {
609
+ androidPermissions: [
610
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.android?.permissions ?? []))
611
+ ].sort(),
612
+ iosPrivacyAccessedApis: IOS_PRIVACY_ACCESSED_APIS.flatMap((api) => {
613
+ const reasons = privacy[api];
614
+ return reasons ? [{ api, reasons: [...reasons].sort() }] : [];
615
+ }),
616
+ iosPushNotifications: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.pushNotifications === true),
617
+ iosSystemBars: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.systemBars === true),
618
+ iosUsageDescriptions: [
619
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.ios?.usageDescriptions ?? []))
620
+ ].sort()
621
+ };
622
+ };
623
+ var resolveAdapterManifest = (adapter, provider) => {
624
+ try {
625
+ return fileURLToPath(import.meta.resolve(`${adapter}/package.json`));
626
+ } catch {
627
+ throw new TypeError(`${adapter} is not installed. Run \`absolute mobile init\` to install the ${provider === "expo" ? "Expo" : "Capacitor"} device adapters.`);
628
+ }
629
+ };
630
+ var loadAbsoluteDeviceCapabilityProviders = (projectRoot, provider = "capacitor") => {
631
+ const adapter = ADAPTERS[provider];
632
+ let path = join2(resolve2(projectRoot), "node_modules", adapter, "package.json");
633
+ try {
634
+ readFileSync2(path, "utf8");
635
+ } catch {
636
+ path = resolveAdapterManifest(adapter, provider);
637
+ }
638
+ const manifest = readJson(path);
639
+ const { absolutejs } = manifest;
640
+ const devices = object2(absolutejs) ? absolutejs.devices : undefined;
641
+ if (!object2(devices) || devices.format !== 1 || devices.provider !== provider || !object2(devices.capabilities))
642
+ throw new TypeError(`${adapter} does not publish supported capability metadata.`);
643
+ const entries = Object.entries(devices.capabilities).map(([name, capability]) => ({
644
+ name,
645
+ provider: parseProvider(name, capability, provider)
646
+ }));
647
+ return Object.fromEntries(entries.sort((left, right) => left.name.localeCompare(right.name)).map(({ name, provider: capabilityProvider }) => [
648
+ name,
649
+ capabilityProvider
650
+ ]));
651
+ };
652
+ var isIgnored = (path) => path.split("/").some((segment) => IGNORED_DIRECTORIES.has(segment));
653
+ var importedCapabilities = (source, file) => {
654
+ const names = new Set;
655
+ const namespaces = new Set;
656
+ const visit = (node) => {
657
+ if (lazyTypescript.isImportDeclaration(node) && lazyTypescript.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && !node.importClause?.isTypeOnly) {
658
+ const bindings = node.importClause?.namedBindings;
659
+ if (bindings && lazyTypescript.isNamedImports(bindings)) {
660
+ for (const element of bindings.elements)
661
+ if (!element.isTypeOnly)
662
+ names.add((element.propertyName ?? element.name).text);
663
+ }
664
+ if (bindings && lazyTypescript.isNamespaceImport(bindings))
665
+ namespaces.add(bindings.name.text);
666
+ }
667
+ if (lazyTypescript.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && lazyTypescript.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && node.exportClause && lazyTypescript.isNamedExports(node.exportClause)) {
668
+ for (const element of node.exportClause.elements)
669
+ if (!element.isTypeOnly)
670
+ names.add((element.propertyName ?? element.name).text);
671
+ }
672
+ if (lazyTypescript.isPropertyAccessExpression(node) && lazyTypescript.isIdentifier(node.expression) && namespaces.has(node.expression.text))
673
+ names.add(node.name.text);
674
+ lazyTypescript.forEachChild(node, visit);
675
+ };
676
+ const extension = extname(file).toLowerCase();
677
+ const sources = extension === ".svelte" || extension === ".vue" ? [...source.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script\s*>/giu)].map((match) => match[1]).filter((value) => value !== undefined) : [source];
678
+ for (const [index, script] of sources.entries())
679
+ visit(lazyTypescript.createSourceFile(`${file}#script-${index}`, script, lazyTypescript.ScriptTarget.Latest, true, lazyTypescript.ScriptKind.TSX));
680
+ return names;
681
+ };
682
+ var assertAbsoluteDeviceCapabilityPackages = (projectRoot, plan) => {
683
+ const missing = missingAbsoluteDeviceCapabilityPackages(plan, directAbsoluteProjectPackages(projectRoot));
684
+ const mismatched = plan.requiredPackages.filter((spec) => {
685
+ const separator = spec.lastIndexOf("@");
686
+ const packageName = spec.slice(0, separator);
687
+ if (missing.includes(spec))
688
+ return false;
689
+ try {
690
+ return readJson(join2(resolve2(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
691
+ } catch {
692
+ return true;
693
+ }
694
+ });
695
+ const unmet = [...missing, ...mismatched];
696
+ if (unmet.length > 0)
697
+ throw new TypeError(`Device capabilities ${plan.capabilities.join(", ")} require ${unmet.join(", ")}. Run absolute mobile sync and approve the detected capability plugins.`);
698
+ };
699
+ var directAbsoluteProjectPackages = (projectRoot) => {
700
+ const manifest = readJson(join2(resolve2(projectRoot), "package.json"));
701
+ const packages = new Set;
702
+ for (const field of ["dependencies", "devDependencies"]) {
703
+ const dependencies = manifest[field];
704
+ if (object2(dependencies))
705
+ for (const name of Object.keys(dependencies))
706
+ packages.add(name);
707
+ }
708
+ return packages;
709
+ };
710
+ var discoverAbsoluteDeviceCapabilities = (projectRoot, providers = loadAbsoluteDeviceCapabilityProviders(projectRoot)) => {
711
+ const root = resolve2(projectRoot);
712
+ if (!existsSync(root))
713
+ return [];
714
+ const known = new Set(Object.keys(providers));
715
+ const capabilities = new Set;
716
+ for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
717
+ const portable = relative(root, resolve2(root, path)).replaceAll("\\", "/");
718
+ if (isIgnored(portable))
719
+ continue;
720
+ const source = readFileSync2(resolve2(root, portable), "utf8");
721
+ for (const name of importedCapabilities(source, portable))
722
+ if (known.has(name))
723
+ capabilities.add(name);
724
+ }
725
+ return [...capabilities].sort();
726
+ };
727
+ var missingAbsoluteDeviceCapabilityPackages = (plan, directPackages) => plan.requiredPackages.filter((spec) => {
728
+ const packageName = spec.slice(0, spec.lastIndexOf("@"));
729
+ return !directPackages.has(packageName);
730
+ });
731
+ var resolveAbsoluteDeviceCapabilityPlan = (projectRoot, provider = "capacitor") => {
732
+ const allProviders = loadAbsoluteDeviceCapabilityProviders(projectRoot, provider);
733
+ const capabilities = discoverAbsoluteDeviceCapabilities(projectRoot, allProviders);
734
+ for (const capability of ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABILITIES) {
735
+ if (allProviders[capability] && !capabilities.includes(capability))
736
+ capabilities.push(capability);
737
+ }
738
+ capabilities.sort();
739
+ const providers = {};
740
+ for (const name of capabilities) {
741
+ const capabilityProvider = allProviders[name];
742
+ if (capabilityProvider)
743
+ providers[name] = capabilityProvider;
744
+ }
745
+ return {
746
+ capabilities,
747
+ providers,
748
+ requiredPackages: [
749
+ ...new Set(capabilities.flatMap((name) => providers[name]?.packages ?? []))
750
+ ].sort()
751
+ };
752
+ };
753
+
754
+ export { discoverAbsoluteSyncSchema, absoluteDeviceNativeRequirements, assertAbsoluteDeviceCapabilityPackages, resolveAbsoluteDeviceCapabilityPlan };