@axonpack/preview 0.0.0-stage → 0.1.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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/android/build.gradle +21 -0
- package/android/consumer-rules.pro +3 -0
- package/android/src/main/java/expo/modules/axonpackpreview/AxonpackPreviewModule.kt +72 -0
- package/android/src/main/java/expo/modules/axonpackpreview/BundleLoaderOverride.kt +41 -0
- package/android/src/main/java/expo/modules/axonpackpreview/HermesHeader.kt +24 -0
- package/android/src/main/java/expo/modules/axonpackpreview/PreviewPackage.kt +76 -0
- package/android/src/main/java/expo/modules/axonpackpreview/PreviewState.kt +295 -0
- package/app.plugin.js +112 -0
- package/bin/preview.js +2 -0
- package/build/cli.cjs +1465 -0
- package/build/cli.d.ts +3 -0
- package/build/cli.d.ts.map +1 -0
- package/build/cli.js +164 -0
- package/build/cli.js.map +1 -0
- package/build/components/preview-list/preview-list.component.d.ts +13 -0
- package/build/components/preview-list/preview-list.component.d.ts.map +1 -0
- package/build/components/preview-list/preview-list.component.js +316 -0
- package/build/components/preview-list/preview-list.component.js.map +1 -0
- package/build/components/preview-list/preview-list.types.d.ts +59 -0
- package/build/components/preview-list/preview-list.types.d.ts.map +1 -0
- package/build/components/preview-list/preview-list.types.js +2 -0
- package/build/components/preview-list/preview-list.types.js.map +1 -0
- package/build/components/preview-provider/preview-provider.component.d.ts +12 -0
- package/build/components/preview-provider/preview-provider.component.d.ts.map +1 -0
- package/build/components/preview-provider/preview-provider.component.js +19 -0
- package/build/components/preview-provider/preview-provider.component.js.map +1 -0
- package/build/constants/dev-preview-servers/dev-preview-servers.const.d.ts +26 -0
- package/build/constants/dev-preview-servers/dev-preview-servers.const.d.ts.map +1 -0
- package/build/constants/dev-preview-servers/dev-preview-servers.const.js +9 -0
- package/build/constants/dev-preview-servers/dev-preview-servers.const.js.map +1 -0
- package/build/constants/preview-list/theme.const.d.ts +5 -0
- package/build/constants/preview-list/theme.const.d.ts.map +1 -0
- package/build/constants/preview-list/theme.const.js +65 -0
- package/build/constants/preview-list/theme.const.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +16 -0
- package/build/index.js.map +1 -0
- package/build/services/cli/config.service.d.ts +13 -0
- package/build/services/cli/config.service.d.ts.map +1 -0
- package/build/services/cli/config.service.js +39 -0
- package/build/services/cli/config.service.js.map +1 -0
- package/build/services/cli/project.service.d.ts +25 -0
- package/build/services/cli/project.service.d.ts.map +1 -0
- package/build/services/cli/project.service.js +81 -0
- package/build/services/cli/project.service.js.map +1 -0
- package/build/services/cli/title.service.d.ts +15 -0
- package/build/services/cli/title.service.d.ts.map +1 -0
- package/build/services/cli/title.service.js +24 -0
- package/build/services/cli/title.service.js.map +1 -0
- package/build/services/dev-preview-servers/discover.service.d.ts +14 -0
- package/build/services/dev-preview-servers/discover.service.d.ts.map +1 -0
- package/build/services/dev-preview-servers/discover.service.js +106 -0
- package/build/services/dev-preview-servers/discover.service.js.map +1 -0
- package/build/services/native/build-info.service.d.ts +11 -0
- package/build/services/native/build-info.service.d.ts.map +1 -0
- package/build/services/native/build-info.service.js +18 -0
- package/build/services/native/build-info.service.js.map +1 -0
- package/build/services/native/native.service.d.ts +24 -0
- package/build/services/native/native.service.d.ts.map +1 -0
- package/build/services/native/native.service.js +13 -0
- package/build/services/native/native.service.js.map +1 -0
- package/build/services/previews/download.service.d.ts +14 -0
- package/build/services/previews/download.service.d.ts.map +1 -0
- package/build/services/previews/download.service.js +66 -0
- package/build/services/previews/download.service.js.map +1 -0
- package/build/services/previews/local-previews.service.d.ts +25 -0
- package/build/services/previews/local-previews.service.d.ts.map +1 -0
- package/build/services/previews/local-previews.service.js +50 -0
- package/build/services/previews/local-previews.service.js.map +1 -0
- package/build/services/previews/reload.service.d.ts +6 -0
- package/build/services/previews/reload.service.d.ts.map +1 -0
- package/build/services/previews/reload.service.js +13 -0
- package/build/services/previews/reload.service.js.map +1 -0
- package/build/services/previews/remote.service.d.ts +11 -0
- package/build/services/previews/remote.service.d.ts.map +1 -0
- package/build/services/previews/remote.service.js +34 -0
- package/build/services/previews/remote.service.js.map +1 -0
- package/build/services/previews/select.service.d.ts +11 -0
- package/build/services/previews/select.service.d.ts.map +1 -0
- package/build/services/previews/select.service.js +25 -0
- package/build/services/previews/select.service.js.map +1 -0
- package/build/services/previews/use-preview.service.d.ts +21 -0
- package/build/services/previews/use-preview.service.d.ts.map +1 -0
- package/build/services/previews/use-preview.service.js +24 -0
- package/build/services/previews/use-preview.service.js.map +1 -0
- package/build/services/previews/use-running.service.d.ts +4 -0
- package/build/services/previews/use-running.service.d.ts.map +1 -0
- package/build/services/previews/use-running.service.js +21 -0
- package/build/services/previews/use-running.service.js.map +1 -0
- package/build/services/publish/bundle.service.d.ts +11 -0
- package/build/services/publish/bundle.service.d.ts.map +1 -0
- package/build/services/publish/bundle.service.js +46 -0
- package/build/services/publish/bundle.service.js.map +1 -0
- package/build/services/publish/commands.service.d.ts +23 -0
- package/build/services/publish/commands.service.d.ts.map +1 -0
- package/build/services/publish/commands.service.js +130 -0
- package/build/services/publish/commands.service.js.map +1 -0
- package/build/services/publish/eas-env.service.d.ts +9 -0
- package/build/services/publish/eas-env.service.d.ts.map +1 -0
- package/build/services/publish/eas-env.service.js +49 -0
- package/build/services/publish/eas-env.service.js.map +1 -0
- package/build/services/registry/registry.service.d.ts +27 -0
- package/build/services/registry/registry.service.d.ts.map +1 -0
- package/build/services/registry/registry.service.js +89 -0
- package/build/services/registry/registry.service.js.map +1 -0
- package/build/services/s3/s3.service.d.ts +59 -0
- package/build/services/s3/s3.service.d.ts.map +1 -0
- package/build/services/s3/s3.service.js +154 -0
- package/build/services/s3/s3.service.js.map +1 -0
- package/build/services/start/start.service.d.ts +48 -0
- package/build/services/start/start.service.d.ts.map +1 -0
- package/build/services/start/start.service.js +172 -0
- package/build/services/start/start.service.js.map +1 -0
- package/build/stores/dev-preview-servers/dev-preview-servers.store.d.ts +21 -0
- package/build/stores/dev-preview-servers/dev-preview-servers.store.d.ts.map +1 -0
- package/build/stores/dev-preview-servers/dev-preview-servers.store.js +91 -0
- package/build/stores/dev-preview-servers/dev-preview-servers.store.js.map +1 -0
- package/build/stores/previews/previews.store.d.ts +36 -0
- package/build/stores/previews/previews.store.d.ts.map +1 -0
- package/build/stores/previews/previews.store.js +134 -0
- package/build/stores/previews/previews.store.js.map +1 -0
- package/build/utils/config/config.util.d.ts +39 -0
- package/build/utils/config/config.util.d.ts.map +1 -0
- package/build/utils/config/config.util.js +24 -0
- package/build/utils/config/config.util.js.map +1 -0
- package/build/utils/config/expo-config.util.d.ts +30 -0
- package/build/utils/config/expo-config.util.d.ts.map +1 -0
- package/build/utils/config/expo-config.util.js +43 -0
- package/build/utils/config/expo-config.util.js.map +1 -0
- package/build/utils/dev-preview-servers/merge-servers.util.d.ts +47 -0
- package/build/utils/dev-preview-servers/merge-servers.util.d.ts.map +1 -0
- package/build/utils/dev-preview-servers/merge-servers.util.js +37 -0
- package/build/utils/dev-preview-servers/merge-servers.util.js.map +1 -0
- package/build/utils/preview-list/theme.util.d.ts +5 -0
- package/build/utils/preview-list/theme.util.d.ts.map +1 -0
- package/build/utils/preview-list/theme.util.js +12 -0
- package/build/utils/preview-list/theme.util.js.map +1 -0
- package/build/utils/previews/layout.util.d.ts +89 -0
- package/build/utils/previews/layout.util.d.ts.map +1 -0
- package/build/utils/previews/layout.util.js +30 -0
- package/build/utils/previews/layout.util.js.map +1 -0
- package/build/utils/previews/preview-items.util.d.ts +23 -0
- package/build/utils/previews/preview-items.util.d.ts.map +1 -0
- package/build/utils/previews/preview-items.util.js +39 -0
- package/build/utils/previews/preview-items.util.js.map +1 -0
- package/build/utils/previews/preview-title.util.d.ts +2 -0
- package/build/utils/previews/preview-title.util.d.ts.map +1 -0
- package/build/utils/previews/preview-title.util.js +6 -0
- package/build/utils/previews/preview-title.util.js.map +1 -0
- package/build/utils/previews/running.util.d.ts +23 -0
- package/build/utils/previews/running.util.d.ts.map +1 -0
- package/build/utils/previews/running.util.js +23 -0
- package/build/utils/previews/running.util.js.map +1 -0
- package/build/utils/publish/changelog.util.d.ts +5 -0
- package/build/utils/publish/changelog.util.d.ts.map +1 -0
- package/build/utils/publish/changelog.util.js +19 -0
- package/build/utils/publish/changelog.util.js.map +1 -0
- package/build/utils/publish/indexes.util.d.ts +12 -0
- package/build/utils/publish/indexes.util.d.ts.map +1 -0
- package/build/utils/publish/indexes.util.js +52 -0
- package/build/utils/publish/indexes.util.js.map +1 -0
- package/build/utils/s3/sigv4.util.d.ts +24 -0
- package/build/utils/s3/sigv4.util.d.ts.map +1 -0
- package/build/utils/s3/sigv4.util.js +67 -0
- package/build/utils/s3/sigv4.util.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/AxonpackPreview.podspec +30 -0
- package/ios/AxonpackPreviewModule.swift +55 -0
- package/ios/PreviewReactDelegateHandler.swift +147 -0
- package/ios/PreviewState.swift +236 -0
- package/notes/README.md +36 -0
- package/notes/bundles.md +35 -0
- package/notes/dev-preview-servers.md +67 -0
- package/notes/distribution.md +138 -0
- package/notes/native-loader.md +56 -0
- package/notes/storage.md +145 -0
- package/notes/testing.md +97 -0
- package/package.json +107 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-items.util.d.ts","sourceRoot":"","sources":["../../../src/utils/previews/preview-items.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAE1E,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,aAAa,GACb,YAAY,GACZ,kBAAkB,GAClB,aAAa,GACb,QAAQ,CAAC;AAEb,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,qFAAqF;IACrF,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG;IAClD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,YAAY,EAAE,YAAY,EAAE,CAAC;CAC9B,CAqCA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list QA sees for this build: everything the bucket offers, plus downloads it no longer lists
|
|
3
|
+
* (unpublished). Downloads for another build go to `incompatible` instead; nothing expires.
|
|
4
|
+
*/
|
|
5
|
+
export function previewItems(state) {
|
|
6
|
+
const compatible = state.local.filter((p) => p.key === state.buildKey);
|
|
7
|
+
const incompatible = state.local.filter((p) => p.key !== state.buildKey);
|
|
8
|
+
const localById = new Map(compatible.map((p) => [p.id, p]));
|
|
9
|
+
const remote = state.remote ?? [];
|
|
10
|
+
const item = (entry, local, listed) => {
|
|
11
|
+
const progress = state.downloading[entry.id] ?? null;
|
|
12
|
+
let status = "available";
|
|
13
|
+
if (progress !== null)
|
|
14
|
+
status = "downloading";
|
|
15
|
+
else if (local && state.broken.includes(entry.id))
|
|
16
|
+
status = "broken";
|
|
17
|
+
else if (local && !listed && state.remote !== null)
|
|
18
|
+
status = "unpublished";
|
|
19
|
+
else if (local && listed && local.revision !== entry.revision)
|
|
20
|
+
status = "update-available";
|
|
21
|
+
else if (local)
|
|
22
|
+
status = "downloaded";
|
|
23
|
+
return {
|
|
24
|
+
id: entry.id,
|
|
25
|
+
entry,
|
|
26
|
+
status,
|
|
27
|
+
progress,
|
|
28
|
+
active: state.activeId === entry.id,
|
|
29
|
+
local,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const items = remote.map((entry) => item(entry, localById.get(entry.id) ?? null, true));
|
|
33
|
+
for (const local of compatible) {
|
|
34
|
+
if (!remote.some((entry) => entry.id === local.id))
|
|
35
|
+
items.push(item(local.entry, local, false));
|
|
36
|
+
}
|
|
37
|
+
return { items, incompatible };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=preview-items.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-items.util.js","sourceRoot":"","sources":["../../../src/utils/previews/preview-items.util.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAoB;IAI/C,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;IAElC,MAAM,IAAI,GAAG,CACX,KAAiB,EACjB,KAA0B,EAC1B,MAAe,EACF,EAAE;QACf,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;QACrD,IAAI,MAAM,GAAkB,WAAW,CAAC;QACxC,IAAI,QAAQ,KAAK,IAAI;YAAE,MAAM,GAAG,aAAa,CAAC;aACzC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,MAAM,GAAG,QAAQ,CAAC;aAChE,IAAI,KAAK,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;YAAE,MAAM,GAAG,aAAa,CAAC;aACtE,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;YAC3D,MAAM,GAAG,kBAAkB,CAAC;aACzB,IAAI,KAAK;YAAE,MAAM,GAAG,YAAY,CAAC;QACtC,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,KAAK;YACL,MAAM;YACN,QAAQ;YACR,MAAM,EAAE,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,EAAE;YACnC,KAAK;SACN,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACjC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CACnD,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC;YAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;AACjC,CAAC","sourcesContent":["import type { IndexEntry } from \"./layout.util\";\nimport type { LocalPreview } from \"../../services/previews/local-previews.service\";\nimport type { PreviewsState } from \"../../stores/previews/previews.store\";\n\nexport type PreviewStatus =\n | \"available\"\n | \"downloading\"\n | \"downloaded\"\n | \"update-available\"\n | \"unpublished\"\n | \"broken\";\n\nexport type PreviewItem = {\n id: string;\n /** The bucket's entry, or the one saved with the download once it is unpublished. */\n entry: IndexEntry;\n status: PreviewStatus;\n /** 0 to 1 while downloading. */\n progress: number | null;\n active: boolean;\n local: LocalPreview | null;\n};\n\n/**\n * The list QA sees for this build: everything the bucket offers, plus downloads it no longer lists\n * (unpublished). Downloads for another build go to `incompatible` instead; nothing expires.\n */\nexport function previewItems(state: PreviewsState): {\n items: PreviewItem[];\n incompatible: LocalPreview[];\n} {\n const compatible = state.local.filter((p) => p.key === state.buildKey);\n const incompatible = state.local.filter((p) => p.key !== state.buildKey);\n const localById = new Map(compatible.map((p) => [p.id, p]));\n const remote = state.remote ?? [];\n\n const item = (\n entry: IndexEntry,\n local: LocalPreview | null,\n listed: boolean,\n ): PreviewItem => {\n const progress = state.downloading[entry.id] ?? null;\n let status: PreviewStatus = \"available\";\n if (progress !== null) status = \"downloading\";\n else if (local && state.broken.includes(entry.id)) status = \"broken\";\n else if (local && !listed && state.remote !== null) status = \"unpublished\";\n else if (local && listed && local.revision !== entry.revision)\n status = \"update-available\";\n else if (local) status = \"downloaded\";\n return {\n id: entry.id,\n entry,\n status,\n progress,\n active: state.activeId === entry.id,\n local,\n };\n };\n\n const items = remote.map((entry) =>\n item(entry, localById.get(entry.id) ?? null, true),\n );\n for (const local of compatible) {\n if (!remote.some((entry) => entry.id === local.id))\n items.push(item(local.entry, local, false));\n }\n return { items, incompatible };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-title.util.d.ts","sourceRoot":"","sources":["../../../src/utils/previews/preview-title.util.ts"],"names":[],"mappings":"AACA,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGnD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The preview id is the branch name, so this is what QA reads when no `--title` was given.
|
|
2
|
+
export function previewTitle(branch) {
|
|
3
|
+
const words = branch.replace(/[-_/]+/g, " ").trim();
|
|
4
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=preview-title.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-title.util.js","sourceRoot":"","sources":["../../../src/utils/previews/preview-title.util.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC","sourcesContent":["// The preview id is the branch name, so this is what QA reads when no `--title` was given.\nexport function previewTitle(branch: string): string {\n const words = branch.replace(/[-_/]+/g, \" \").trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DevPreviewServer } from "../dev-preview-servers/merge-servers.util";
|
|
2
|
+
import type { PreviewItem } from "./preview-items.util";
|
|
3
|
+
/** What this start runs: a local Metro server, a downloaded preview, or the app's own bundle. */
|
|
4
|
+
export type Running = {
|
|
5
|
+
kind: "local";
|
|
6
|
+
url: string;
|
|
7
|
+
hostPort: string;
|
|
8
|
+
/** Null until the dev preview servers list has found it. */
|
|
9
|
+
server: DevPreviewServer | null;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "preview";
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "base";
|
|
16
|
+
};
|
|
17
|
+
export declare function runningNow(input: {
|
|
18
|
+
items: PreviewItem[];
|
|
19
|
+
activeId: string | null;
|
|
20
|
+
localUrl: string | null;
|
|
21
|
+
servers: DevPreviewServer[];
|
|
22
|
+
}): Running;
|
|
23
|
+
//# sourceMappingURL=running.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"running.util.d.ts","sourceRoot":"","sources":["../../../src/utils/previews/running.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,iGAAiG;AACjG,MAAM,MAAM,OAAO,GACf;IACE,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAChC,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B,GAAG,OAAO,CAsBV"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function runningNow(input) {
|
|
2
|
+
const { localUrl } = input;
|
|
3
|
+
// A dev preview server wins over a picked preview on the native side, so it wins here too.
|
|
4
|
+
if (localUrl) {
|
|
5
|
+
const server = input.servers.find((s) => s.url === localUrl) ?? null;
|
|
6
|
+
return {
|
|
7
|
+
kind: "local",
|
|
8
|
+
url: localUrl,
|
|
9
|
+
hostPort: server?.hostPort ?? localUrl.replace(/^\w+:\/\/([^/]+).*$/, "$1"),
|
|
10
|
+
server,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (input.activeId) {
|
|
14
|
+
const item = input.items.find((i) => i.active);
|
|
15
|
+
return {
|
|
16
|
+
kind: "preview",
|
|
17
|
+
id: input.activeId,
|
|
18
|
+
title: item?.entry.title ?? input.activeId,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return { kind: "base" };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=running.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"running.util.js","sourceRoot":"","sources":["../../../src/utils/previews/running.util.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,UAAU,CAAC,KAK1B;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC3B,2FAA2F;IAC3F,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC;QACrE,OAAO;YACL,IAAI,EAAE,OAAO;YACb,GAAG,EAAE,QAAQ;YACb,QAAQ,EACN,MAAM,EAAE,QAAQ,IAAI,QAAQ,CAAC,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC;YACnE,MAAM;SACP,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO;YACL,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,KAAK,CAAC,QAAQ;YAClB,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ;SAC3C,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC","sourcesContent":["import type { DevPreviewServer } from \"../dev-preview-servers/merge-servers.util\";\nimport type { PreviewItem } from \"./preview-items.util\";\n\n/** What this start runs: a local Metro server, a downloaded preview, or the app's own bundle. */\nexport type Running =\n | {\n kind: \"local\";\n url: string;\n hostPort: string;\n /** Null until the dev preview servers list has found it. */\n server: DevPreviewServer | null;\n }\n | { kind: \"preview\"; id: string; title: string }\n | { kind: \"base\" };\n\nexport function runningNow(input: {\n items: PreviewItem[];\n activeId: string | null;\n localUrl: string | null;\n servers: DevPreviewServer[];\n}): Running {\n const { localUrl } = input;\n // A dev preview server wins over a picked preview on the native side, so it wins here too.\n if (localUrl) {\n const server = input.servers.find((s) => s.url === localUrl) ?? null;\n return {\n kind: \"local\",\n url: localUrl,\n hostPort:\n server?.hostPort ?? localUrl.replace(/^\\w+:\\/\\/([^/]+).*$/, \"$1\"),\n server,\n };\n }\n if (input.activeId) {\n const item = input.items.find((i) => i.active);\n return {\n kind: \"preview\",\n id: input.activeId,\n title: item?.entry.title ?? input.activeId,\n };\n }\n return { kind: \"base\" };\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** One line per commit subject, newest first, the way `git log` lists them. */
|
|
2
|
+
export declare function changelogFromSubjects(subjects: string[]): string;
|
|
3
|
+
/** The index carries a short form, so the list stays small; the manifest keeps the whole text. */
|
|
4
|
+
export declare function shortChangelog(changelog: string, maxLines?: number, maxChars?: number): string;
|
|
5
|
+
//# sourceMappingURL=changelog.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.util.d.ts","sourceRoot":"","sources":["../../../src/utils/publish/changelog.util.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMhE;AAED,kGAAkG;AAClG,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAI,EACZ,QAAQ,SAAM,GACb,MAAM,CAQR"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** One line per commit subject, newest first, the way `git log` lists them. */
|
|
2
|
+
export function changelogFromSubjects(subjects) {
|
|
3
|
+
return subjects
|
|
4
|
+
.map((s) => s.trim())
|
|
5
|
+
.filter(Boolean)
|
|
6
|
+
.map((s) => `- ${s}`)
|
|
7
|
+
.join("\n");
|
|
8
|
+
}
|
|
9
|
+
/** The index carries a short form, so the list stays small; the manifest keeps the whole text. */
|
|
10
|
+
export function shortChangelog(changelog, maxLines = 3, maxChars = 280) {
|
|
11
|
+
const lines = changelog.split("\n").filter((l) => l.trim());
|
|
12
|
+
let short = lines.slice(0, maxLines).join("\n");
|
|
13
|
+
if (short.length > maxChars)
|
|
14
|
+
short = `${short.slice(0, maxChars - 1).trimEnd()}…`;
|
|
15
|
+
else if (lines.length > maxLines)
|
|
16
|
+
short += `\n… ${lines.length - maxLines} more`;
|
|
17
|
+
return short;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=changelog.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.util.js","sourceRoot":"","sources":["../../../src/utils/publish/changelog.util.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB,CAAC,QAAkB;IACtD,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;SACpB,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,cAAc,CAC5B,SAAiB,EACjB,QAAQ,GAAG,CAAC,EACZ,QAAQ,GAAG,GAAG;IAEd,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ;QACzB,KAAK,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;SAClD,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ;QAC9B,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,OAAO,CAAC;IACjD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/** One line per commit subject, newest first, the way `git log` lists them. */\nexport function changelogFromSubjects(subjects: string[]): string {\n return subjects\n .map((s) => s.trim())\n .filter(Boolean)\n .map((s) => `- ${s}`)\n .join(\"\\n\");\n}\n\n/** The index carries a short form, so the list stays small; the manifest keeps the whole text. */\nexport function shortChangelog(\n changelog: string,\n maxLines = 3,\n maxChars = 280,\n): string {\n const lines = changelog.split(\"\\n\").filter((l) => l.trim());\n let short = lines.slice(0, maxLines).join(\"\\n\");\n if (short.length > maxChars)\n short = `${short.slice(0, maxChars - 1).trimEnd()}…`;\n else if (lines.length > maxLines)\n short += `\\n… ${lines.length - maxLines} more`;\n return short;\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Compatibility, PlatformIndex, IndexEntry, Platform, RootIndex } from "../previews/layout.util";
|
|
2
|
+
/** Adds the entry, or replaces the one with the same id. */
|
|
3
|
+
export declare function upsertPreview(index: PlatformIndex | null, platform: Platform, build: {
|
|
4
|
+
key: string;
|
|
5
|
+
compatibility: Compatibility;
|
|
6
|
+
}, entry: IndexEntry, now: string): PlatformIndex;
|
|
7
|
+
export declare function removePreview(index: PlatformIndex, id: string, now: string): PlatformIndex;
|
|
8
|
+
/** Mirrors one platform index into the top-level list; a build left with no previews drops out. */
|
|
9
|
+
export declare function syncRootVersion(root: RootIndex | null, index: PlatformIndex, now: string): RootIndex;
|
|
10
|
+
/** Every platform index that lists the id, from the top-level list. */
|
|
11
|
+
export declare const indexesListing: (root: RootIndex | null, id: string) => string[];
|
|
12
|
+
//# sourceMappingURL=indexes.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexes.util.d.ts","sourceRoot":"","sources":["../../../src/utils/publish/indexes.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,SAAS,EAIV,MAAM,yBAAyB,CAAC;AAKjC,4DAA4D;AAC5D,wBAAgB,aAAa,CAC3B,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,aAAa,CAAA;CAAE,EACpD,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,GACV,aAAa,CAUf;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,GACV,aAAa,CAMf;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,GAAG,IAAI,EACtB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,GACV,SAAS,CA0BX;AAED,uEAAuE;AACvE,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,GAAG,IAAI,EAAE,IAAI,MAAM,KAAG,MAAM,EAGlD,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SCHEMA, platformIndexKey, } from "../previews/layout.util";
|
|
2
|
+
const newestFirst = (a, b) => b.publishedAt.localeCompare(a.publishedAt);
|
|
3
|
+
/** Adds the entry, or replaces the one with the same id. */
|
|
4
|
+
export function upsertPreview(index, platform, build, entry, now) {
|
|
5
|
+
const others = (index?.previews ?? []).filter((p) => p.id !== entry.id);
|
|
6
|
+
return {
|
|
7
|
+
schema: SCHEMA,
|
|
8
|
+
platform,
|
|
9
|
+
key: build.key,
|
|
10
|
+
compatibility: build.compatibility,
|
|
11
|
+
updatedAt: now,
|
|
12
|
+
previews: [...others, entry].sort(newestFirst),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function removePreview(index, id, now) {
|
|
16
|
+
return {
|
|
17
|
+
...index,
|
|
18
|
+
updatedAt: now,
|
|
19
|
+
previews: index.previews.filter((p) => p.id !== id),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Mirrors one platform index into the top-level list; a build left with no previews drops out. */
|
|
23
|
+
export function syncRootVersion(root, index, now) {
|
|
24
|
+
const versions = (root?.versions ?? []).filter((v) => !(v.platform === index.platform && v.key === index.key));
|
|
25
|
+
if (index.previews.length > 0) {
|
|
26
|
+
const latest = index.previews[0];
|
|
27
|
+
const version = {
|
|
28
|
+
platform: index.platform,
|
|
29
|
+
key: index.key,
|
|
30
|
+
compatibility: index.compatibility,
|
|
31
|
+
appVersion: latest.appVersion,
|
|
32
|
+
buildNumber: latest.buildNumber,
|
|
33
|
+
fingerprint: latest.fingerprint,
|
|
34
|
+
count: index.previews.length,
|
|
35
|
+
updatedAt: now,
|
|
36
|
+
index: platformIndexKey(index.platform, index.key),
|
|
37
|
+
previews: index.previews.map(({ id, title, publishedAt }) => ({
|
|
38
|
+
id,
|
|
39
|
+
title,
|
|
40
|
+
publishedAt,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
versions.push(version);
|
|
44
|
+
}
|
|
45
|
+
versions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
46
|
+
return { schema: SCHEMA, updatedAt: now, versions };
|
|
47
|
+
}
|
|
48
|
+
/** Every platform index that lists the id, from the top-level list. */
|
|
49
|
+
export const indexesListing = (root, id) => (root?.versions ?? [])
|
|
50
|
+
.filter((v) => v.previews.some((p) => p.id === id))
|
|
51
|
+
.map((v) => v.index);
|
|
52
|
+
//# sourceMappingURL=indexes.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexes.util.js","sourceRoot":"","sources":["../../../src/utils/publish/indexes.util.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Compatibility,\n PlatformIndex,\n IndexEntry,\n Platform,\n RootIndex,\n RootVersion,\n SCHEMA,\n platformIndexKey,\n} from \"../previews/layout.util\";\n\nconst newestFirst = (a: { publishedAt: string }, b: { publishedAt: string }) =>\n b.publishedAt.localeCompare(a.publishedAt);\n\n/** Adds the entry, or replaces the one with the same id. */\nexport function upsertPreview(\n index: PlatformIndex | null,\n platform: Platform,\n build: { key: string; compatibility: Compatibility },\n entry: IndexEntry,\n now: string,\n): PlatformIndex {\n const others = (index?.previews ?? []).filter((p) => p.id !== entry.id);\n return {\n schema: SCHEMA,\n platform,\n key: build.key,\n compatibility: build.compatibility,\n updatedAt: now,\n previews: [...others, entry].sort(newestFirst),\n };\n}\n\nexport function removePreview(\n index: PlatformIndex,\n id: string,\n now: string,\n): PlatformIndex {\n return {\n ...index,\n updatedAt: now,\n previews: index.previews.filter((p) => p.id !== id),\n };\n}\n\n/** Mirrors one platform index into the top-level list; a build left with no previews drops out. */\nexport function syncRootVersion(\n root: RootIndex | null,\n index: PlatformIndex,\n now: string,\n): RootIndex {\n const versions = (root?.versions ?? []).filter(\n (v) => !(v.platform === index.platform && v.key === index.key),\n );\n if (index.previews.length > 0) {\n const latest = index.previews[0];\n const version: RootVersion = {\n platform: index.platform,\n key: index.key,\n compatibility: index.compatibility,\n appVersion: latest.appVersion,\n buildNumber: latest.buildNumber,\n fingerprint: latest.fingerprint,\n count: index.previews.length,\n updatedAt: now,\n index: platformIndexKey(index.platform, index.key),\n previews: index.previews.map(({ id, title, publishedAt }) => ({\n id,\n title,\n publishedAt,\n })),\n };\n versions.push(version);\n }\n versions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n return { schema: SCHEMA, updatedAt: now, versions };\n}\n\n/** Every platform index that lists the id, from the top-level list. */\nexport const indexesListing = (root: RootIndex | null, id: string): string[] =>\n (root?.versions ?? [])\n .filter((v) => v.previews.some((p) => p.id === id))\n .map((v) => v.index);\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type Credentials = {
|
|
2
|
+
accessKeyId: string;
|
|
3
|
+
secretAccessKey: string;
|
|
4
|
+
sessionToken?: string;
|
|
5
|
+
};
|
|
6
|
+
export type SignInput = {
|
|
7
|
+
method: string;
|
|
8
|
+
url: string;
|
|
9
|
+
region: string;
|
|
10
|
+
credentials: Credentials;
|
|
11
|
+
/** Headers to send and sign. Host comes from the URL. */
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
/** Hex sha256 of the body, or "UNSIGNED-PAYLOAD". Defaults to the hash of an empty body. */
|
|
14
|
+
payloadHash?: string;
|
|
15
|
+
service?: string;
|
|
16
|
+
date?: Date;
|
|
17
|
+
/** S3 needs `x-amz-content-sha256`; the generic AWS test suite signs without it. */
|
|
18
|
+
addContentSha256?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare const EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
|
21
|
+
export declare const sha256Hex: (data: Uint8Array | string) => string;
|
|
22
|
+
/** Returns the headers to send: the input headers plus the date, hash and Authorization. */
|
|
23
|
+
export declare function signRequest(input: SignInput): Record<string, string>;
|
|
24
|
+
//# sourceMappingURL=sigv4.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.util.d.ts","sourceRoot":"","sources":["../../../src/utils/s3/sigv4.util.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,WAAW,CAAC;IACzB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,YAAY,qEAC2C,CAAC;AAErE,eAAO,MAAM,SAAS,GAAI,MAAM,UAAU,GAAG,MAAM,KAAG,MACmB,CAAC;AAsC1E,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgDpE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
+
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
4
|
+
export const EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
|
5
|
+
export const sha256Hex = (data) => bytesToHex(sha256(typeof data === "string" ? utf8ToBytes(data) : data));
|
|
6
|
+
const hmacBytes = (key, data) => hmac(sha256, typeof key === "string" ? utf8ToBytes(key) : key, utf8ToBytes(data));
|
|
7
|
+
// RFC 3986: everything but unreserved characters is percent-encoded, which encodeURIComponent
|
|
8
|
+
// almost does; it leaves !'()* alone.
|
|
9
|
+
const encode = (value) => encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
10
|
+
const canonicalPath = (pathname) => pathname
|
|
11
|
+
.split("/")
|
|
12
|
+
.map((segment) => encode(decodeURIComponent(segment)))
|
|
13
|
+
.join("/") || "/";
|
|
14
|
+
const canonicalQuery = (search) => [...search.entries()]
|
|
15
|
+
.map(([key, value]) => [encode(key), encode(value)])
|
|
16
|
+
.sort(([ak, av], [bk, bv]) => ak === bk ? (av < bv ? -1 : 1) : ak < bk ? -1 : 1)
|
|
17
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
18
|
+
.join("&");
|
|
19
|
+
const amzDate = (date) => date
|
|
20
|
+
.toISOString()
|
|
21
|
+
.replace(/[-:]/g, "")
|
|
22
|
+
.replace(/\.\d{3}/, "");
|
|
23
|
+
/** Returns the headers to send: the input headers plus the date, hash and Authorization. */
|
|
24
|
+
export function signRequest(input) {
|
|
25
|
+
const url = new URL(input.url);
|
|
26
|
+
const service = input.service ?? "s3";
|
|
27
|
+
const payloadHash = input.payloadHash ?? EMPTY_SHA256;
|
|
28
|
+
const timestamp = amzDate(input.date ?? new Date());
|
|
29
|
+
const day = timestamp.slice(0, 8);
|
|
30
|
+
const headers = { ...input.headers };
|
|
31
|
+
headers["x-amz-date"] = timestamp;
|
|
32
|
+
if (input.addContentSha256 ?? true)
|
|
33
|
+
headers["x-amz-content-sha256"] = payloadHash;
|
|
34
|
+
if (input.credentials.sessionToken) {
|
|
35
|
+
headers["x-amz-security-token"] = input.credentials.sessionToken;
|
|
36
|
+
}
|
|
37
|
+
const signed = new Map();
|
|
38
|
+
signed.set("host", url.host);
|
|
39
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
40
|
+
signed.set(name.toLowerCase(), value.trim().replace(/\s+/g, " "));
|
|
41
|
+
}
|
|
42
|
+
const names = [...signed.keys()].sort();
|
|
43
|
+
const signedHeaders = names.join(";");
|
|
44
|
+
const canonicalRequest = [
|
|
45
|
+
input.method.toUpperCase(),
|
|
46
|
+
canonicalPath(url.pathname),
|
|
47
|
+
canonicalQuery(url.searchParams),
|
|
48
|
+
names.map((name) => `${name}:${signed.get(name)}\n`).join(""),
|
|
49
|
+
signedHeaders,
|
|
50
|
+
payloadHash,
|
|
51
|
+
].join("\n");
|
|
52
|
+
const scope = `${day}/${input.region}/${service}/aws4_request`;
|
|
53
|
+
const stringToSign = [
|
|
54
|
+
"AWS4-HMAC-SHA256",
|
|
55
|
+
timestamp,
|
|
56
|
+
scope,
|
|
57
|
+
sha256Hex(canonicalRequest),
|
|
58
|
+
].join("\n");
|
|
59
|
+
let key = hmacBytes(`AWS4${input.credentials.secretAccessKey}`, day);
|
|
60
|
+
key = hmacBytes(key, input.region);
|
|
61
|
+
key = hmacBytes(key, service);
|
|
62
|
+
key = hmacBytes(key, "aws4_request");
|
|
63
|
+
const signature = bytesToHex(hmacBytes(key, stringToSign));
|
|
64
|
+
headers.Authorization = `AWS4-HMAC-SHA256 Credential=${input.credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
65
|
+
return headers;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=sigv4.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.util.js","sourceRoot":"","sources":["../../../src/utils/s3/sigv4.util.ts"],"names":[],"mappings":"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","sourcesContent":["import { hmac } from \"@noble/hashes/hmac.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex, utf8ToBytes } from \"@noble/hashes/utils.js\";\n\n// AWS Signature Version 4, header form. Pure JS so the same code signs uploads in the CLI (Node)\n// and private-bucket downloads in the app (Hermes, which has no WebCrypto).\n\nexport type Credentials = {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n};\n\nexport type SignInput = {\n method: string;\n url: string;\n region: string;\n credentials: Credentials;\n /** Headers to send and sign. Host comes from the URL. */\n headers?: Record<string, string>;\n /** Hex sha256 of the body, or \"UNSIGNED-PAYLOAD\". Defaults to the hash of an empty body. */\n payloadHash?: string;\n service?: string;\n date?: Date;\n /** S3 needs `x-amz-content-sha256`; the generic AWS test suite signs without it. */\n addContentSha256?: boolean;\n};\n\nexport const EMPTY_SHA256 =\n \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\nexport const sha256Hex = (data: Uint8Array | string): string =>\n bytesToHex(sha256(typeof data === \"string\" ? utf8ToBytes(data) : data));\n\nconst hmacBytes = (key: Uint8Array | string, data: string): Uint8Array =>\n hmac(\n sha256,\n typeof key === \"string\" ? utf8ToBytes(key) : key,\n utf8ToBytes(data),\n );\n\n// RFC 3986: everything but unreserved characters is percent-encoded, which encodeURIComponent\n// almost does; it leaves !'()* alone.\nconst encode = (value: string): string =>\n encodeURIComponent(value).replace(\n /[!'()*]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n\nconst canonicalPath = (pathname: string): string =>\n pathname\n .split(\"/\")\n .map((segment) => encode(decodeURIComponent(segment)))\n .join(\"/\") || \"/\";\n\nconst canonicalQuery = (search: URLSearchParams): string =>\n [...search.entries()]\n .map(([key, value]) => [encode(key), encode(value)])\n .sort(([ak, av], [bk, bv]) =>\n ak === bk ? (av < bv ? -1 : 1) : ak < bk ? -1 : 1,\n )\n .map(([key, value]) => `${key}=${value}`)\n .join(\"&\");\n\nconst amzDate = (date: Date): string =>\n date\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\.\\d{3}/, \"\");\n\n/** Returns the headers to send: the input headers plus the date, hash and Authorization. */\nexport function signRequest(input: SignInput): Record<string, string> {\n const url = new URL(input.url);\n const service = input.service ?? \"s3\";\n const payloadHash = input.payloadHash ?? EMPTY_SHA256;\n const timestamp = amzDate(input.date ?? new Date());\n const day = timestamp.slice(0, 8);\n\n const headers: Record<string, string> = { ...input.headers };\n headers[\"x-amz-date\"] = timestamp;\n if (input.addContentSha256 ?? true)\n headers[\"x-amz-content-sha256\"] = payloadHash;\n if (input.credentials.sessionToken) {\n headers[\"x-amz-security-token\"] = input.credentials.sessionToken;\n }\n\n const signed = new Map<string, string>();\n signed.set(\"host\", url.host);\n for (const [name, value] of Object.entries(headers)) {\n signed.set(name.toLowerCase(), value.trim().replace(/\\s+/g, \" \"));\n }\n const names = [...signed.keys()].sort();\n const signedHeaders = names.join(\";\");\n\n const canonicalRequest = [\n input.method.toUpperCase(),\n canonicalPath(url.pathname),\n canonicalQuery(url.searchParams),\n names.map((name) => `${name}:${signed.get(name)}\\n`).join(\"\"),\n signedHeaders,\n payloadHash,\n ].join(\"\\n\");\n\n const scope = `${day}/${input.region}/${service}/aws4_request`;\n const stringToSign = [\n \"AWS4-HMAC-SHA256\",\n timestamp,\n scope,\n sha256Hex(canonicalRequest),\n ].join(\"\\n\");\n\n let key = hmacBytes(`AWS4${input.credentials.secretAccessKey}`, day);\n key = hmacBytes(key, input.region);\n key = hmacBytes(key, service);\n key = hmacBytes(key, \"aws4_request\");\n const signature = bytesToHex(hmacBytes(key, stringToSign));\n\n headers.Authorization = `AWS4-HMAC-SHA256 Credential=${input.credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;\n return headers;\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'AxonpackPreview'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = {
|
|
14
|
+
:ios => '16.4',
|
|
15
|
+
:tvos => '16.4'
|
|
16
|
+
}
|
|
17
|
+
s.swift_version = '5.9'
|
|
18
|
+
s.source = { git: 'https://github.com/axonpack/axonpack.git' }
|
|
19
|
+
s.static_framework = true
|
|
20
|
+
|
|
21
|
+
s.dependency 'ExpoModulesCore'
|
|
22
|
+
# RCTReloadCommand, to restart into a newly chosen bundle.
|
|
23
|
+
s.dependency 'React-Core'
|
|
24
|
+
|
|
25
|
+
s.source_files = "**/*.{h,m,swift}"
|
|
26
|
+
s.pod_target_xcconfig = {
|
|
27
|
+
'DEFINES_MODULE' => 'YES',
|
|
28
|
+
'SWIFT_COMPILATION_MODE' => 'wholemodule'
|
|
29
|
+
}
|
|
30
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
public final class AxonpackPreviewModule: Module {
|
|
5
|
+
public func definition() -> ModuleDefinition {
|
|
6
|
+
Name("AxonpackPreview")
|
|
7
|
+
|
|
8
|
+
// What the config plugin wrote at prebuild; nil when the plugin is not in the app config.
|
|
9
|
+
Constants([
|
|
10
|
+
"compatibility": Bundle.main.object(forInfoDictionaryKey: "AxonpackPreviewCompatibility") as? String,
|
|
11
|
+
"key": Bundle.main.object(forInfoDictionaryKey: "AxonpackPreviewKey") as? String,
|
|
12
|
+
"slug": Bundle.main.object(forInfoDictionaryKey: "AxonpackPreviewSlug") as? String
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
OnCreate {
|
|
16
|
+
DispatchQueue.main.async {
|
|
17
|
+
PreviewReactDelegateHandler.startOnSelectedPreview()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Function("select") { (bundle: String?, key: String?) in
|
|
22
|
+
try PreviewState.select(bundle, key: key)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// `hostPort` is what Android needs; iOS loads the bundle URL itself.
|
|
26
|
+
Function("selectLocalServer") { (url: String?, _: String?) in
|
|
27
|
+
PreviewState.selectLocalServer(url)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Function("state") {
|
|
31
|
+
PreviewState.read()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Function("markLaunched") {
|
|
35
|
+
PreviewState.confirmStart()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Function("reload") {
|
|
39
|
+
guard PreviewState.newArchitecture else {
|
|
40
|
+
PreviewState.warnOldArchitecture()
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
// The reload asks the bundle URL block again, and that block reads the current choice.
|
|
44
|
+
DispatchQueue.main.async {
|
|
45
|
+
PreviewReactDelegateHandler.reload()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
final class PreviewPathOutsideException: Exception {
|
|
52
|
+
override var reason: String {
|
|
53
|
+
"The bundle path must stay inside the preview folder"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Makes the app's bundle URL ask `state.json` every time React reads it: at the first start and on
|
|
6
|
+
every reload. A selected preview wins; otherwise the app's own URL is used, so Metro in a debug
|
|
7
|
+
build, the embedded bundle in a release build, or expo-updates' update loads exactly as without
|
|
8
|
+
this package.
|
|
9
|
+
|
|
10
|
+
React keeps the URL block it was created with, so it is swapped before the first root view exists,
|
|
11
|
+
which is when this handler runs. Returning nil lets the normal root view be made with the new block.
|
|
12
|
+
expo-updates is ordered ahead of every other handler and answers itself, so with it active this
|
|
13
|
+
handler is not asked; the module then reloads into a selected preview once it starts
|
|
14
|
+
(`startOnSelectedPreview`).
|
|
15
|
+
*/
|
|
16
|
+
public final class PreviewReactDelegateHandler: ExpoReactDelegateHandler {
|
|
17
|
+
private typealias BundleURLBlock = @convention(block) () -> URL?
|
|
18
|
+
|
|
19
|
+
private static var installed = false
|
|
20
|
+
private static var hopped = false
|
|
21
|
+
private static weak var rootViewFactory: NSObject?
|
|
22
|
+
/// What the block handed React last, to tell whether the running bundle is the selected one.
|
|
23
|
+
private static var lastServed: URL?
|
|
24
|
+
|
|
25
|
+
public override func createReactRootView(
|
|
26
|
+
reactDelegate: ExpoReactDelegate,
|
|
27
|
+
moduleName: String,
|
|
28
|
+
initialProperties: [AnyHashable: Any]?,
|
|
29
|
+
launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
30
|
+
) -> UIView? {
|
|
31
|
+
Self.install(factory: reactDelegate.reactNativeFactory as? NSObject)
|
|
32
|
+
return nil
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private static func install(factory: NSObject?) {
|
|
36
|
+
if installed {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
// React's factory and its configuration are reached by key, the way Expo's own
|
|
40
|
+
// `recreateRootView` reads `_configuration`, so this needs no header from React's app delegate pod.
|
|
41
|
+
guard
|
|
42
|
+
let factory,
|
|
43
|
+
factory.responds(to: NSSelectorFromString("rootViewFactory")),
|
|
44
|
+
let rootViewFactory = factory.value(forKey: "rootViewFactory") as? NSObject,
|
|
45
|
+
let configuration = rootViewFactory.value(forKey: "_configuration") as? NSObject,
|
|
46
|
+
configuration.responds(to: NSSelectorFromString("bundleURLBlock")),
|
|
47
|
+
let current = configuration.value(forKey: "bundleURLBlock")
|
|
48
|
+
else {
|
|
49
|
+
previewLog.warning("Could not reach React's bundle URL, so previews are off and the base bundle loads")
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
Self.rootViewFactory = rootViewFactory
|
|
53
|
+
let base = unsafeBitCast(current as AnyObject, to: BundleURLBlock.self)
|
|
54
|
+
let block: BundleURLBlock = {
|
|
55
|
+
// A local Metro server wins over a downloaded preview and the default (debug builds only).
|
|
56
|
+
let url = PreviewState.localServerURL ?? PreviewState.bundleToLoad() ?? base()
|
|
57
|
+
Self.lastServed = url
|
|
58
|
+
return url
|
|
59
|
+
}
|
|
60
|
+
configuration.setValue(block, forKey: "bundleURLBlock")
|
|
61
|
+
installed = true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
For an app whose start this handler did not see (expo-updates answered first): if a preview is
|
|
66
|
+
selected but the base is what started, reload once into the preview. Once per process, so a
|
|
67
|
+
preview that cannot load never turns into a reload loop.
|
|
68
|
+
*/
|
|
69
|
+
static func startOnSelectedPreview() {
|
|
70
|
+
// The plain lookup, not `bundleToLoad`: that would count this start as a preview start and the
|
|
71
|
+
// reload below as a second one.
|
|
72
|
+
guard
|
|
73
|
+
!hopped,
|
|
74
|
+
PreviewState.localServerURL == nil,
|
|
75
|
+
let preview = PreviewState.selectedBundle(),
|
|
76
|
+
PreviewState.newArchitecture
|
|
77
|
+
else {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
if installed, lastServed?.standardizedFileURL == preview.standardizedFileURL {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
hopped = true
|
|
84
|
+
reload()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
Restarts JS into the current choice. React's bundle manager reads its bundle configuration before
|
|
89
|
+
anything else, and the one Expo builds deliberately says nothing for a file URL. So a preview is
|
|
90
|
+
put there as React's own file configuration, and the base gets React's default one, which hands
|
|
91
|
+
the choice back to the app's URL: Metro, the embedded bundle, or expo-updates' update. This works
|
|
92
|
+
whether or not the block above was installed. Each step is checked, since a missing key throws.
|
|
93
|
+
*/
|
|
94
|
+
static func reload() {
|
|
95
|
+
PreviewState.nextStart()
|
|
96
|
+
guard
|
|
97
|
+
let host = reactHost(),
|
|
98
|
+
let ivar = class_getInstanceVariable(type(of: host), "_bundleManager"),
|
|
99
|
+
let manager = object_getIvar(host, ivar) as? NSObject,
|
|
100
|
+
manager.responds(to: NSSelectorFromString("setBundleConfig:")),
|
|
101
|
+
let configuration = bundleConfiguration(
|
|
102
|
+
for: PreviewState.localServerURL == nil ? PreviewState.bundleToLoad() : nil
|
|
103
|
+
)
|
|
104
|
+
else {
|
|
105
|
+
previewLog.warning("Could not reach React's bundle manager, so the reload keeps the current bundle")
|
|
106
|
+
RCTTriggerReloadCommandListeners("preview: switch bundle")
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
manager.setValue(configuration, forKey: "bundleConfig")
|
|
110
|
+
RCTTriggerReloadCommandListeners("preview: switch bundle")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private static func reactHost() -> NSObject? {
|
|
114
|
+
var factory = rootViewFactory
|
|
115
|
+
if factory == nil {
|
|
116
|
+
// The handler was not asked, so find React's factory where Expo's app delegate template keeps it.
|
|
117
|
+
let appDelegate = UIApplication.shared.delegate as? NSObject
|
|
118
|
+
if appDelegate?.responds(to: NSSelectorFromString("reactNativeFactory")) == true,
|
|
119
|
+
let reactNativeFactory = appDelegate?.value(forKey: "reactNativeFactory") as? NSObject,
|
|
120
|
+
reactNativeFactory.responds(to: NSSelectorFromString("rootViewFactory")) {
|
|
121
|
+
factory = reactNativeFactory.value(forKey: "rootViewFactory") as? NSObject
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
guard let factory, factory.responds(to: NSSelectorFromString("reactHost")) else {
|
|
125
|
+
return nil
|
|
126
|
+
}
|
|
127
|
+
return factory.value(forKey: "reactHost") as? NSObject
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private static func bundleConfiguration(for preview: URL?) -> NSObject? {
|
|
131
|
+
guard
|
|
132
|
+
let type = NSClassFromString("RCTBundleConfiguration") as? NSObject.Type,
|
|
133
|
+
type.responds(to: NSSelectorFromString("defaultConfiguration")),
|
|
134
|
+
let configuration = type.perform(NSSelectorFromString("defaultConfiguration"))?.takeUnretainedValue() as? NSObject
|
|
135
|
+
else {
|
|
136
|
+
return nil
|
|
137
|
+
}
|
|
138
|
+
guard let preview else {
|
|
139
|
+
return configuration
|
|
140
|
+
}
|
|
141
|
+
guard class_getInstanceVariable(type, "_bundleFilePath") != nil else {
|
|
142
|
+
return nil
|
|
143
|
+
}
|
|
144
|
+
configuration.setValue(preview as NSURL, forKey: "bundleFilePath")
|
|
145
|
+
return configuration
|
|
146
|
+
}
|
|
147
|
+
}
|