@agnostack/next-shopify 4.0.0-canary.9 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/dist/esm/lib/utils/session.js +5 -16
- package/dist/esm/shared/storage.js +5 -0
- package/dist/lib/utils/session.js +5 -16
- package/dist/shared/storage.js +5 -0
- package/dist/shared/types.d.ts +2 -2
- package/package.json +4 -20
- package/dist/esm/storage/firestore.js +0 -79
- package/dist/storage/firestore.d.ts +0 -4
- package/dist/storage/firestore.js +0 -83
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,101 @@
|
|
|
1
|
+
# [4.0.0](https://github.com/agnostack/next-shopify/compare/v3.3.0...v4.0.0) (2026-10-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
* feat!: require a storage implementation rather than bundling one ([a13f021](https://github.com/agnostack/next-shopify/commit/a13f02143b0836a35e0506443ec9fdbf674518db))
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* add dev copies of the required peers so checkJs can resolve them ([6c7fdd2](https://github.com/agnostack/next-shopify/commit/6c7fdd2ce0f6094bc0477b48cea39be189bc1329))
|
|
10
|
+
* add pnpm-lock.yaml ([bfc803a](https://github.com/agnostack/next-shopify/commit/bfc803a3e758d72e13a1f201cff266f43a28665d))
|
|
11
|
+
* address the review notes on the checkjs stack ([52dca8d](https://github.com/agnostack/next-shopify/commit/52dca8d006f6d7f192982d5a91c5b814041127ec))
|
|
12
|
+
* align .gitignore with the shared template ([5968bf1](https://github.com/agnostack/next-shopify/commit/5968bf193a32cd0c4f3f45f6d71694b8f872961c))
|
|
13
|
+
* build and test against firebase-admin 14.4.0 ([cf75069](https://github.com/agnostack/next-shopify/commit/cf75069fab599ab29d8e2d95068c91044c7ae191))
|
|
14
|
+
* bump cookies to 0.9.1 ([6e7554c](https://github.com/agnostack/next-shopify/commit/6e7554c3bd85bc57f9bffcafecd7c65564d06160))
|
|
15
|
+
* bump isbot to 5.2.2 and import it by name ([30c1228](https://github.com/agnostack/next-shopify/commit/30c12288f1754809d25a4c9db2334d09c487db08))
|
|
16
|
+
* bump js-base64 to 3.9.3 ([7543e32](https://github.com/agnostack/next-shopify/commit/7543e3220f5b9d265a1ee205caff08d0ef0cf1ae))
|
|
17
|
+
* bump jwt-decode to 4.0.0 ([bc5df03](https://github.com/agnostack/next-shopify/commit/bc5df03761dc691566833ea9fa5e1e93622befb1))
|
|
18
|
+
* bump minimatch to 10.2.6 ([8aa0dc6](https://github.com/agnostack/next-shopify/commit/8aa0dc61678a778522409e2659baa490728d8e2b))
|
|
19
|
+
* bump nextjs-cors to 2.2.1 ([173860d](https://github.com/agnostack/next-shopify/commit/173860dd166f8e7eaade280f5480dcd207f637a6))
|
|
20
|
+
* bump uuid to 11.1.1 and drop its stub typings ([fa02d50](https://github.com/agnostack/next-shopify/commit/fa02d50b52540577a7191fb9b5e02dcba63213c9))
|
|
21
|
+
* cap the firebase-admin peer below 14 ([42b2b32](https://github.com/agnostack/next-shopify/commit/42b2b3259184e623418209704bfd82c86a56481a)), closes [firebase/firebase-admin-node#3164](https://github.com/firebase/firebase-admin-node/issues/3164)
|
|
22
|
+
* compare ArrayBuffer hashes by their byte length ([1b08a62](https://github.com/agnostack/next-shopify/commit/1b08a623fceea251b1721c39fa9907c77b22bb7f))
|
|
23
|
+
* compile the CommonJS sources for the node that can require esm ([f30407a](https://github.com/agnostack/next-shopify/commit/f30407a77e4344d9d6a410b921a9b17edfc891c5))
|
|
24
|
+
* declare typescript as 5.x like the rest of the toolchain ([a1e7ee3](https://github.com/agnostack/next-shopify/commit/a1e7ee38f8bd189265f1590811236ddb29b839af))
|
|
25
|
+
* decode zstd in the proxy response adapter and fail closed on unknown encodings ([cdcd8a5](https://github.com/agnostack/next-shopify/commit/cdcd8a559e9ff772bdcd4e42ce46a3ebf6fca92c))
|
|
26
|
+
* drop jsonwebtoken ([5abb88c](https://github.com/agnostack/next-shopify/commit/5abb88c466e967134ca785c005067566150d4965))
|
|
27
|
+
* fail clearly when the shopify api is bypassed instead of with a TypeError ([d7e647e](https://github.com/agnostack/next-shopify/commit/d7e647e0fd75ffb4e5a09b203768720f6460b153))
|
|
28
|
+
* float firebase-admin to 14.x ([5784493](https://github.com/agnostack/next-shopify/commit/5784493cdbcb3130f54299b364d61f29b0179bdb))
|
|
29
|
+
* float the http-proxy devDependency to 1.18.x ([825819b](https://github.com/agnostack/next-shopify/commit/825819b0e39e8d3b4ef62fec9dfc8ff8a90a924b))
|
|
30
|
+
* give the dual export subpaths a default condition ([10c2c90](https://github.com/agnostack/next-shopify/commit/10c2c9024ccab238444249551d32aeda9520be21))
|
|
31
|
+
* give the test workflow read-only permissions and cancel superseded runs ([2b26326](https://github.com/agnostack/next-shopify/commit/2b26326d78b6bc7c02eac948009e24191dd6274f))
|
|
32
|
+
* hand isbot a string for the User-Agent lookup ([2b42b4c](https://github.com/agnostack/next-shopify/commit/2b42b4c588af3ed0358904e3fffeed2e8401a010))
|
|
33
|
+
* import jsonwebtoken as a default so the esm build links under native node ([3db30d9](https://github.com/agnostack/next-shopify/commit/3db30d9b9d8a6882de7ff714e93b2fc3df3eece2))
|
|
34
|
+
* inflate proxied responses in the adapter so corrupt bodies fail closed ([3056b5d](https://github.com/agnostack/next-shopify/commit/3056b5df9a351368725111feeed7d7371e652e56))
|
|
35
|
+
* keep the storage contract and its implementations in one tree ([2b380e7](https://github.com/agnostack/next-shopify/commit/2b380e789d41385d56f2c4464917db32e888beb1))
|
|
36
|
+
* keep the storage contract in shared and the storage folder for implementations ([e862a11](https://github.com/agnostack/next-shopify/commit/e862a1129b71668fcae431b164ba66e1e51906e7))
|
|
37
|
+
* mark the version-signalling peers optional ([87b2c6d](https://github.com/agnostack/next-shopify/commit/87b2c6de6d7cdd89b9a9b60be56c7955fa85e3df))
|
|
38
|
+
* move both workflows to checkout v6, pnpm/action-setup v6 and setup-node v5 ([46669e7](https://github.com/agnostack/next-shopify/commit/46669e73fd17862726970d622c232486df5eaac5))
|
|
39
|
+
* move the session handler to the modular firebase-admin imports ([0ef15fc](https://github.com/agnostack/next-shopify/commit/0ef15fc7a26a8a6989ca0ec5831d762504e5a89f))
|
|
40
|
+
* move vitest to 4.x ([2b0b7de](https://github.com/agnostack/next-shopify/commit/2b0b7de7b70120cda4b1051a89a1848137e1e377))
|
|
41
|
+
* name getShopifyHelpers' return type so its declaration is emitted ([e871d98](https://github.com/agnostack/next-shopify/commit/e871d987d0ad93d8c8e9442a512067e2ba531bb3))
|
|
42
|
+
* notes and a GitHub release on every publishing branch, changelog only on stable releases ([2c9ad23](https://github.com/agnostack/next-shopify/commit/2c9ad2356a0c3f834bac8423d900078513d0eca0))
|
|
43
|
+
* queue overlapping release runs instead of cancelling them ([d75f9dc](https://github.com/agnostack/next-shopify/commit/d75f9dc0c246e3388b28ef4c4a1429140e8248dd))
|
|
44
|
+
* raise the next and react peer floors to the versions the app runs ([1efb9c9](https://github.com/agnostack/next-shopify/commit/1efb9c95a2c41e6b97a89e1c76610de4a3df7039))
|
|
45
|
+
* read the proxied content-encoding case-insensitively and treat identity as none ([d2e0351](https://github.com/agnostack/next-shopify/commit/d2e03513e93212a95f2cb1c0b6d3173285f5dd0a))
|
|
46
|
+
* reflow the checkJs JSDoc into multi-line blocks and drop the inline parameter casts ([73e855e](https://github.com/agnostack/next-shopify/commit/73e855ea290b13b6eccee5afbd066269f077dcff))
|
|
47
|
+
* replace node-http-proxy-json with a typed responseInterceptor adapter ([45bd502](https://github.com/agnostack/next-shopify/commit/45bd502bf98fb1ddfe057d05e35f6deae123143c))
|
|
48
|
+
* reset the proxied response immediately when the upstream aborts mid-body ([c14225e](https://github.com/agnostack/next-shopify/commit/c14225e10767c1781617d8e4e7d499b2e63d8ab7))
|
|
49
|
+
* resolve modules with node16 and split the tsconfigs ([9b87dd2](https://github.com/agnostack/next-shopify/commit/9b87dd2316c16f0c3272f4b1b57e72233b599e52))
|
|
50
|
+
* run semantic-release through pnpm exec so package keywords are not masked ([39cd371](https://github.com/agnostack/next-shopify/commit/39cd371007223b2bb1bda10c99a907f8ad91b486))
|
|
51
|
+
* satisfy the typecheck and pin the stored document paths ([83b2691](https://github.com/agnostack/next-shopify/commit/83b2691ddaf0b2e5f6b4fe0309a12bd6c56115ee))
|
|
52
|
+
* sign extension session tokens with jose ([0c3b0c0](https://github.com/agnostack/next-shopify/commit/0c3b0c00e017a42d25867032a78c18ada7881d15))
|
|
53
|
+
* skip CI on the release commit ([c277847](https://github.com/agnostack/next-shopify/commit/c277847f20d97eef849a9438945727e898d964e1))
|
|
54
|
+
* standardize version ([6fe44c5](https://github.com/agnostack/next-shopify/commit/6fe44c5ead19be5740ecd6ca58ddad82426f8ed3))
|
|
55
|
+
* standardize version ([4218665](https://github.com/agnostack/next-shopify/commit/42186651b7604a8438a4a01fedb940f5efae4f73))
|
|
56
|
+
* suffix relative imports so the esm build links under native node ([c73827e](https://github.com/agnostack/next-shopify/commit/c73827eea42044c980d11330abe3a5ee6a3a9893))
|
|
57
|
+
* take unknown in ensureStorage, since that is what it is deciding ([5a8a3f8](https://github.com/agnostack/next-shopify/commit/5a8a3f88fd18c5654e0928ab9c69626cd7ec2356))
|
|
58
|
+
* throw a clear error when CryptoHandler is used before it is initialized ([db17f06](https://github.com/agnostack/next-shopify/commit/db17f06ccc489feaa0af7cd5347f2f96cd09d078))
|
|
59
|
+
* type state as the consumer's own data rather than as opaque ([ca13e28](https://github.com/agnostack/next-shopify/commit/ca13e28f1e7f91a8c39c74f516e998c7848f8d0f))
|
|
60
|
+
* type the public helpers surface so it stops discarding the contract ([77088dd](https://github.com/agnostack/next-shopify/commit/77088dd4718a7de119c9446ba52df8648f47a388))
|
|
61
|
+
* type the storage contract so an implementation cannot read what it stores ([06c05bf](https://github.com/agnostack/next-shopify/commit/06c05bf80af1d5b1c2cc3fa8c4d0195e533daf33))
|
|
62
|
+
* type-check the js sources ([61f0783](https://github.com/agnostack/next-shopify/commit/61f0783e7e0108af8304b80a9d6391856afa40c3))
|
|
63
|
+
* verify extension session tokens with jose ([b436d11](https://github.com/agnostack/next-shopify/commit/b436d11b75f09470a98667130937a69753531ed4))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
### chore
|
|
67
|
+
|
|
68
|
+
* modernize the toolchain to node 22, pnpm, eslint 9 and vitest ([0cc5cd4](https://github.com/agnostack/next-shopify/commit/0cc5cd4648ae2d173d192018ae204836b064bac8))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### Features
|
|
72
|
+
|
|
73
|
+
* add ESM output and /esm + /shared subpath exports ([52c7c15](https://github.com/agnostack/next-shopify/commit/52c7c1530eaee759c3a02adb663f3d68d6bffe47))
|
|
74
|
+
* declare a session-storage contract and accept an implementation ([9f22481](https://github.com/agnostack/next-shopify/commit/9f22481f4cc65e6edfe908a0505a7daecab75ea3))
|
|
75
|
+
* enable npm trusted publishing with the token as fallback ([e72f5d2](https://github.com/agnostack/next-shopify/commit/e72f5d241e38569814b870c10fb0e499ff82baac))
|
|
76
|
+
* preview the release a labelled PR would cut ([746674c](https://github.com/agnostack/next-shopify/commit/746674c46d52136e706d7559c6daa5334eb6d88b)), closes [#67](https://github.com/agnostack/next-shopify/issues/67)
|
|
77
|
+
* replaced getAPIConfig with API_CONFIG page config literal ([d452ee9](https://github.com/agnostack/next-shopify/commit/d452ee90232a392fc4056ca11451a49a35736e00))
|
|
78
|
+
* thread the storage contract through every handler factory ([e3dfa32](https://github.com/agnostack/next-shopify/commit/e3dfa32a00358bb5bb78236f0d96dec1acebcd0a)), closes [#204](https://github.com/agnostack/next-shopify/issues/204)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### BREAKING CHANGES
|
|
82
|
+
|
|
83
|
+
* getShopifyHelpers no longer falls back to a bundled firestore
|
|
84
|
+
store. Every consumer must pass `storage`; omitting it now throws at composition
|
|
85
|
+
instead of silently writing sessions to a store this package chose. The
|
|
86
|
+
./storage/firestore export and the firebase-admin peer are removed with it.
|
|
87
|
+
|
|
88
|
+
Also recorded here because 4.0.0-canary.9 shipped it under a `fix:` type: the
|
|
89
|
+
./storage export was retired in favour of ./shared, which carries the contract,
|
|
90
|
+
its types and ensureStorage.
|
|
91
|
+
|
|
92
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
93
|
+
* requires node >=22.
|
|
94
|
+
|
|
95
|
+
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
96
|
+
* getAPIConfig has been removed — calling it in `export const config` is a fatal build error under next 15's static analyzer. Use the named re-export:
|
|
97
|
+
`export { API_CONFIG as config } from '@agnostack/next-shopify/lib'`
|
|
98
|
+
|
|
1
99
|
# [3.3.0](https://github.com/agnostack/next-shopify/compare/v3.2.2...v3.3.0) (2025-08-20)
|
|
2
100
|
|
|
3
101
|
|
|
@@ -74,37 +74,26 @@ const prepareSessionPayload = (session) => {
|
|
|
74
74
|
const _b = _onlineAccessInfo !== null && _onlineAccessInfo !== void 0 ? _onlineAccessInfo : {}, { associated_user } = _b, onlineAccessInfo = __rest(_b, ["associated_user"]);
|
|
75
75
|
return Object.assign({ onlineAccessInfo }, sessionData);
|
|
76
76
|
};
|
|
77
|
-
// NOTE: imported lazily so an app that supplies its own storage never loads firebase-admin,
|
|
78
|
-
// even though it is still the default. PR 4 removes this branch and the peer with it.
|
|
79
|
-
/**
|
|
80
|
-
* @param {any} firebaseConfig
|
|
81
|
-
* @param {any} options
|
|
82
|
-
*/
|
|
83
|
-
const createDefaultStorage = async (firebaseConfig, options) => {
|
|
84
|
-
const { createFirestoreStorage } = await import('../../storage/firestore.js');
|
|
85
|
-
return createFirestoreStorage(firebaseConfig, options);
|
|
86
|
-
};
|
|
87
77
|
// TODO: move to curry??
|
|
88
78
|
/**
|
|
89
79
|
* @param {any} [serverRuntimeConfig]
|
|
90
80
|
* @param {any} [config]
|
|
91
|
-
* @param {import('../../shared/index.js').StorageOptions}
|
|
81
|
+
* @param {import('../../shared/index.js').StorageOptions} options
|
|
82
|
+
* ⚠️ `storage` is REQUIRED. There is no bundled implementation to fall back to, so omitting it
|
|
83
|
+
* throws here rather than quietly writing sessions somewhere this app does not own.
|
|
92
84
|
* @returns {Promise<import('./types.js').ShopifyHelpers>}
|
|
93
85
|
*/
|
|
94
86
|
export const getShopifyHelpers = async (serverRuntimeConfig, config, { storage: _storage } = {}) => {
|
|
95
87
|
var _a, _b;
|
|
96
88
|
const shopify = getInitializedShopify(serverRuntimeConfig);
|
|
97
|
-
const {
|
|
89
|
+
const { SHOPIFY_RUN_MODE, SESSION_CONFIG, PAYMENT_CONFIG, } = serverRuntimeConfig;
|
|
98
90
|
const { shop } = config !== null && config !== void 0 ? config : {};
|
|
99
91
|
const isReviewMode = isTrue((SHOPIFY_RUN_MODE === 'review') &&
|
|
100
92
|
(PAYMENT_CONFIG === null || PAYMENT_CONFIG === void 0 ? void 0 : PAYMENT_CONFIG.required));
|
|
101
93
|
// TODO: should this use our helper instead (and/or as a fallback)??
|
|
102
94
|
const shopId = (_b = (_a = shopify === null || shopify === void 0 ? void 0 : shopify.utils) === null || _a === void 0 ? void 0 : _a.sanitizeShop) === null || _b === void 0 ? void 0 : _b.call(_a, shop);
|
|
103
95
|
const cryptoHandler = CryptoHandler.getInstance(SESSION_CONFIG);
|
|
104
|
-
const storage = ensureStorage(_storage
|
|
105
|
-
collection: FB_ROOT_COLLECTION,
|
|
106
|
-
configurationId: APP_ID,
|
|
107
|
-
}));
|
|
96
|
+
const storage = ensureStorage(_storage);
|
|
108
97
|
// NOTE: this should handle running in next to test non-shopify functionality
|
|
109
98
|
if (!shopify) {
|
|
110
99
|
return {
|
|
@@ -21,6 +21,11 @@ export const STORAGE_METHODS = [
|
|
|
21
21
|
*/
|
|
22
22
|
export const ensureStorage = (storage) => {
|
|
23
23
|
const candidate = /** @type {Record<string, unknown> | null | undefined} */ (storage);
|
|
24
|
+
// ⚠️ the upgrade path, called out separately: this package used to bundle a firestore store and
|
|
25
|
+
// fall back to it. Listing all seven methods as missing would be true and would not explain why.
|
|
26
|
+
if (!candidate) {
|
|
27
|
+
throw new Error('No session storage supplied. Pass one as `storage` - this package no longer bundles a default.');
|
|
28
|
+
}
|
|
24
29
|
const missing = ensureArray(STORAGE_METHODS).filter((method) => (typeof (candidate === null || candidate === void 0 ? void 0 : candidate[method]) !== 'function'));
|
|
25
30
|
if (missing.length) {
|
|
26
31
|
throw new Error(`Invalid session storage, missing: ${missing.join(', ')}`);
|
|
@@ -78,37 +78,26 @@ const prepareSessionPayload = (session) => {
|
|
|
78
78
|
const _b = _onlineAccessInfo !== null && _onlineAccessInfo !== void 0 ? _onlineAccessInfo : {}, { associated_user } = _b, onlineAccessInfo = __rest(_b, ["associated_user"]);
|
|
79
79
|
return Object.assign({ onlineAccessInfo }, sessionData);
|
|
80
80
|
};
|
|
81
|
-
// NOTE: imported lazily so an app that supplies its own storage never loads firebase-admin,
|
|
82
|
-
// even though it is still the default. PR 4 removes this branch and the peer with it.
|
|
83
|
-
/**
|
|
84
|
-
* @param {any} firebaseConfig
|
|
85
|
-
* @param {any} options
|
|
86
|
-
*/
|
|
87
|
-
const createDefaultStorage = async (firebaseConfig, options) => {
|
|
88
|
-
const { createFirestoreStorage } = await import('../../storage/firestore.js');
|
|
89
|
-
return createFirestoreStorage(firebaseConfig, options);
|
|
90
|
-
};
|
|
91
81
|
// TODO: move to curry??
|
|
92
82
|
/**
|
|
93
83
|
* @param {any} [serverRuntimeConfig]
|
|
94
84
|
* @param {any} [config]
|
|
95
|
-
* @param {import('../../shared/index.js').StorageOptions}
|
|
85
|
+
* @param {import('../../shared/index.js').StorageOptions} options
|
|
86
|
+
* ⚠️ `storage` is REQUIRED. There is no bundled implementation to fall back to, so omitting it
|
|
87
|
+
* throws here rather than quietly writing sessions somewhere this app does not own.
|
|
96
88
|
* @returns {Promise<import('./types.js').ShopifyHelpers>}
|
|
97
89
|
*/
|
|
98
90
|
const getShopifyHelpers = async (serverRuntimeConfig, config, { storage: _storage } = {}) => {
|
|
99
91
|
var _a, _b;
|
|
100
92
|
const shopify = (0, shopify_js_1.getInitializedShopify)(serverRuntimeConfig);
|
|
101
|
-
const {
|
|
93
|
+
const { SHOPIFY_RUN_MODE, SESSION_CONFIG, PAYMENT_CONFIG, } = serverRuntimeConfig;
|
|
102
94
|
const { shop } = config !== null && config !== void 0 ? config : {};
|
|
103
95
|
const isReviewMode = (0, index_js_1.isTrue)((SHOPIFY_RUN_MODE === 'review') &&
|
|
104
96
|
(PAYMENT_CONFIG === null || PAYMENT_CONFIG === void 0 ? void 0 : PAYMENT_CONFIG.required));
|
|
105
97
|
// TODO: should this use our helper instead (and/or as a fallback)??
|
|
106
98
|
const shopId = (_b = (_a = shopify === null || shopify === void 0 ? void 0 : shopify.utils) === null || _a === void 0 ? void 0 : _a.sanitizeShop) === null || _b === void 0 ? void 0 : _b.call(_a, shop);
|
|
107
99
|
const cryptoHandler = crypto_js_1.CryptoHandler.getInstance(SESSION_CONFIG);
|
|
108
|
-
const storage = (0, index_js_2.ensureStorage)(_storage
|
|
109
|
-
collection: FB_ROOT_COLLECTION,
|
|
110
|
-
configurationId: APP_ID,
|
|
111
|
-
}));
|
|
100
|
+
const storage = (0, index_js_2.ensureStorage)(_storage);
|
|
112
101
|
// NOTE: this should handle running in next to test non-shopify functionality
|
|
113
102
|
if (!shopify) {
|
|
114
103
|
return {
|
package/dist/shared/storage.js
CHANGED
|
@@ -24,6 +24,11 @@ exports.STORAGE_METHODS = [
|
|
|
24
24
|
*/
|
|
25
25
|
const ensureStorage = (storage) => {
|
|
26
26
|
const candidate = /** @type {Record<string, unknown> | null | undefined} */ (storage);
|
|
27
|
+
// ⚠️ the upgrade path, called out separately: this package used to bundle a firestore store and
|
|
28
|
+
// fall back to it. Listing all seven methods as missing would be true and would not explain why.
|
|
29
|
+
if (!candidate) {
|
|
30
|
+
throw new Error('No session storage supplied. Pass one as `storage` - this package no longer bundles a default.');
|
|
31
|
+
}
|
|
27
32
|
const missing = (0, display_js_1.ensureArray)(exports.STORAGE_METHODS).filter((method) => (typeof (candidate === null || candidate === void 0 ? void 0 : candidate[method]) !== 'function'));
|
|
28
33
|
if (missing.length) {
|
|
29
34
|
throw new Error(`Invalid session storage, missing: ${missing.join(', ')}`);
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export type SessionRecord = {
|
|
|
30
30
|
export type StoredState = Record<string, unknown>;
|
|
31
31
|
/**
|
|
32
32
|
* What the session layer needs from a store. Two entities, sessions and state, both scoped to a
|
|
33
|
-
* shop.
|
|
34
|
-
*
|
|
33
|
+
* shop. This package ships no implementation: an app owns where its sessions live and passes
|
|
34
|
+
* one in.
|
|
35
35
|
*
|
|
36
36
|
* ⚠️ Values arrive ALREADY ENCRYPTED and already stripped of anything that must not be persisted.
|
|
37
37
|
* An implementation stores and returns what it is handed - it must not inspect, reshape or
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agnostack/next-shopify",
|
|
3
|
-
"version": "4.0.0
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"author": "agnoStack Dev <developers@agnostack.com> (https://agnostack.com)",
|
|
5
5
|
"owner": "agnoStack",
|
|
6
6
|
"description": "Please contact agnoStack via info@agnostack.com for any questions",
|
|
@@ -39,17 +39,6 @@
|
|
|
39
39
|
"import": "./dist/esm/lib/index.js",
|
|
40
40
|
"default": "./dist/esm/lib/index.js"
|
|
41
41
|
},
|
|
42
|
-
"./storage/firestore": {
|
|
43
|
-
"types": "./dist/storage/firestore.d.ts",
|
|
44
|
-
"require": "./dist/storage/firestore.js",
|
|
45
|
-
"import": "./dist/storage/firestore.js",
|
|
46
|
-
"default": "./dist/storage/firestore.js"
|
|
47
|
-
},
|
|
48
|
-
"./storage/firestore/esm": {
|
|
49
|
-
"types": "./dist/storage/firestore.d.ts",
|
|
50
|
-
"import": "./dist/esm/storage/firestore.js",
|
|
51
|
-
"default": "./dist/esm/storage/firestore.js"
|
|
52
|
-
},
|
|
53
42
|
"./runtime": {
|
|
54
43
|
"types": "./dist/runtime/index.d.ts",
|
|
55
44
|
"require": "./dist/runtime/index.js",
|
|
@@ -123,9 +112,9 @@
|
|
|
123
112
|
"uuid": "11.1.1"
|
|
124
113
|
},
|
|
125
114
|
"devDependencies": {
|
|
126
|
-
"@agnostack/env": "
|
|
127
|
-
"@agnostack/next-plugins": "
|
|
128
|
-
"@agnostack/verifyd": "
|
|
115
|
+
"@agnostack/env": "latest",
|
|
116
|
+
"@agnostack/next-plugins": "latest",
|
|
117
|
+
"@agnostack/verifyd": "latest",
|
|
129
118
|
"@commitlint/cli": "21.x",
|
|
130
119
|
"@commitlint/config-conventional": "21.x",
|
|
131
120
|
"@eslint/js": "9.x",
|
|
@@ -141,7 +130,6 @@
|
|
|
141
130
|
"@typescript-eslint/parser": "8.x",
|
|
142
131
|
"eslint": "9.x",
|
|
143
132
|
"eslint-plugin-import": "2.x",
|
|
144
|
-
"firebase-admin": "14.x",
|
|
145
133
|
"globals": "16.x",
|
|
146
134
|
"http-proxy": "1.18.x",
|
|
147
135
|
"husky": "9.x",
|
|
@@ -155,7 +143,6 @@
|
|
|
155
143
|
"@agnostack/env": "*",
|
|
156
144
|
"@agnostack/next-plugins": "*",
|
|
157
145
|
"@agnostack/verifyd": "*",
|
|
158
|
-
"firebase-admin": ">=10.0.0",
|
|
159
146
|
"http-proxy": ">=1.18.1",
|
|
160
147
|
"next": ">=15.0.0",
|
|
161
148
|
"react": ">=18.0.0",
|
|
@@ -164,9 +151,6 @@
|
|
|
164
151
|
"prompts": ">=2.4.0"
|
|
165
152
|
},
|
|
166
153
|
"peerDependenciesMeta": {
|
|
167
|
-
"firebase-admin": {
|
|
168
|
-
"optional": true
|
|
169
|
-
},
|
|
170
154
|
"next": {
|
|
171
155
|
"optional": true
|
|
172
156
|
},
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { cert, getApp, getApps, initializeApp } from 'firebase-admin/app';
|
|
2
|
-
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
|
-
import { objectNotEmpty, ensureArray, stringEmpty, STATE_PREFIX, COLLECTION_ROOT, } from '../shared/index.js';
|
|
4
|
-
// firebase-admin allows one app per process, so an existing one is reused rather than replaced.
|
|
5
|
-
// NOTE: the retired handler also passed `databaseURL`, which configures the Realtime Database.
|
|
6
|
-
// Nothing here has ever used it - no `getDatabase`, no `firebase-admin/database` import.
|
|
7
|
-
/** @param {any} firebaseConfig */
|
|
8
|
-
const initializeFirebaseApp = (firebaseConfig) => (getApps().length
|
|
9
|
-
? getApp()
|
|
10
|
-
: initializeApp({ credential: cert(firebaseConfig) }));
|
|
11
|
-
/**
|
|
12
|
-
* The Firestore implementation of the session-storage contract, kept here so the core never
|
|
13
|
-
* imports firebase-admin. Sessions and state share one collection per shop; state is a single
|
|
14
|
-
* document per shop, prefixed so it cannot collide with a session id.
|
|
15
|
-
*
|
|
16
|
-
* @param {any} firebaseConfig a firebase service-account config
|
|
17
|
-
* @param {{ collection?: string, configurationId: string }} options
|
|
18
|
-
* @returns {import('../shared/types.js').SessionStorage}
|
|
19
|
-
*/
|
|
20
|
-
export const createFirestoreStorage = (firebaseConfig, { collection = COLLECTION_ROOT, configurationId }) => {
|
|
21
|
-
if (!objectNotEmpty(firebaseConfig)) {
|
|
22
|
-
throw new Error('createFirestoreStorage requires a firebase service-account config');
|
|
23
|
-
}
|
|
24
|
-
const firestore = getFirestore(initializeFirebaseApp(firebaseConfig));
|
|
25
|
-
/** @param {any} shop */
|
|
26
|
-
const shopCollection = (shop) => (firestore
|
|
27
|
-
.collection(collection)
|
|
28
|
-
.doc(shop)
|
|
29
|
-
.collection(configurationId));
|
|
30
|
-
/** @param {any} shop */
|
|
31
|
-
const stateRef = (shop) => shopCollection(shop).doc(`${STATE_PREFIX}${shop}`);
|
|
32
|
-
/** @param {any} docRef */
|
|
33
|
-
const readDocument = async (docRef) => {
|
|
34
|
-
const document = await docRef.get();
|
|
35
|
-
return document.exists ? document.data() : undefined;
|
|
36
|
-
};
|
|
37
|
-
/** @type {import('../shared/types.js').SessionStorage} */
|
|
38
|
-
const storage = {
|
|
39
|
-
loadSession: async (shopId, sessionId) => (stringEmpty(sessionId)
|
|
40
|
-
? undefined
|
|
41
|
-
: readDocument(shopCollection(shopId).doc(`${sessionId}`))),
|
|
42
|
-
// NOTE: merge rather than replace. The core writes partial sessions - a billing status
|
|
43
|
-
// update carries no access token - and a replacing write would drop the rest.
|
|
44
|
-
updateSession: async (shopId, session) => {
|
|
45
|
-
const docRef = shopCollection(shopId).doc(session.id);
|
|
46
|
-
await docRef.set(session, { merge: true });
|
|
47
|
-
return readDocument(docRef);
|
|
48
|
-
},
|
|
49
|
-
deleteSessions: async (shopId, sessionIds) => {
|
|
50
|
-
const collectionRef = shopCollection(shopId);
|
|
51
|
-
return Promise.all(ensureArray(sessionIds).map((sessionId) => collectionRef.doc(sessionId).delete()));
|
|
52
|
-
},
|
|
53
|
-
findSessionIds: async (shopId) => {
|
|
54
|
-
// NOTE: empty rather than an error - this is the state on an initial install
|
|
55
|
-
if (stringEmpty(shopId)) {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
const documents = await shopCollection(shopId).get();
|
|
59
|
-
return documents.docs.map((/** @type {any} */ { id }) => id);
|
|
60
|
-
},
|
|
61
|
-
loadState: async (shop) => (stringEmpty(shop)
|
|
62
|
-
? undefined
|
|
63
|
-
: readDocument(stateRef(shop))),
|
|
64
|
-
storeState: async (shop, state) => {
|
|
65
|
-
if (stringEmpty(shop)) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
const docRef = stateRef(shop);
|
|
69
|
-
// the contract hands state over as `unknown` on purpose: it belongs to the consumer and is
|
|
70
|
-
// stored verbatim, so this cast is the implementation declining to look rather than a guess
|
|
71
|
-
await docRef.set(/** @type {any} */ (state));
|
|
72
|
-
return readDocument(docRef);
|
|
73
|
-
},
|
|
74
|
-
deleteState: async (shop) => (stringEmpty(shop)
|
|
75
|
-
? undefined
|
|
76
|
-
: stateRef(shop).delete()),
|
|
77
|
-
};
|
|
78
|
-
return storage;
|
|
79
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createFirestoreStorage = void 0;
|
|
4
|
-
const app_1 = require("firebase-admin/app");
|
|
5
|
-
const firestore_1 = require("firebase-admin/firestore");
|
|
6
|
-
const index_js_1 = require("../shared/index.js");
|
|
7
|
-
// firebase-admin allows one app per process, so an existing one is reused rather than replaced.
|
|
8
|
-
// NOTE: the retired handler also passed `databaseURL`, which configures the Realtime Database.
|
|
9
|
-
// Nothing here has ever used it - no `getDatabase`, no `firebase-admin/database` import.
|
|
10
|
-
/** @param {any} firebaseConfig */
|
|
11
|
-
const initializeFirebaseApp = (firebaseConfig) => ((0, app_1.getApps)().length
|
|
12
|
-
? (0, app_1.getApp)()
|
|
13
|
-
: (0, app_1.initializeApp)({ credential: (0, app_1.cert)(firebaseConfig) }));
|
|
14
|
-
/**
|
|
15
|
-
* The Firestore implementation of the session-storage contract, kept here so the core never
|
|
16
|
-
* imports firebase-admin. Sessions and state share one collection per shop; state is a single
|
|
17
|
-
* document per shop, prefixed so it cannot collide with a session id.
|
|
18
|
-
*
|
|
19
|
-
* @param {any} firebaseConfig a firebase service-account config
|
|
20
|
-
* @param {{ collection?: string, configurationId: string }} options
|
|
21
|
-
* @returns {import('../shared/types.js').SessionStorage}
|
|
22
|
-
*/
|
|
23
|
-
const createFirestoreStorage = (firebaseConfig, { collection = index_js_1.COLLECTION_ROOT, configurationId }) => {
|
|
24
|
-
if (!(0, index_js_1.objectNotEmpty)(firebaseConfig)) {
|
|
25
|
-
throw new Error('createFirestoreStorage requires a firebase service-account config');
|
|
26
|
-
}
|
|
27
|
-
const firestore = (0, firestore_1.getFirestore)(initializeFirebaseApp(firebaseConfig));
|
|
28
|
-
/** @param {any} shop */
|
|
29
|
-
const shopCollection = (shop) => (firestore
|
|
30
|
-
.collection(collection)
|
|
31
|
-
.doc(shop)
|
|
32
|
-
.collection(configurationId));
|
|
33
|
-
/** @param {any} shop */
|
|
34
|
-
const stateRef = (shop) => shopCollection(shop).doc(`${index_js_1.STATE_PREFIX}${shop}`);
|
|
35
|
-
/** @param {any} docRef */
|
|
36
|
-
const readDocument = async (docRef) => {
|
|
37
|
-
const document = await docRef.get();
|
|
38
|
-
return document.exists ? document.data() : undefined;
|
|
39
|
-
};
|
|
40
|
-
/** @type {import('../shared/types.js').SessionStorage} */
|
|
41
|
-
const storage = {
|
|
42
|
-
loadSession: async (shopId, sessionId) => ((0, index_js_1.stringEmpty)(sessionId)
|
|
43
|
-
? undefined
|
|
44
|
-
: readDocument(shopCollection(shopId).doc(`${sessionId}`))),
|
|
45
|
-
// NOTE: merge rather than replace. The core writes partial sessions - a billing status
|
|
46
|
-
// update carries no access token - and a replacing write would drop the rest.
|
|
47
|
-
updateSession: async (shopId, session) => {
|
|
48
|
-
const docRef = shopCollection(shopId).doc(session.id);
|
|
49
|
-
await docRef.set(session, { merge: true });
|
|
50
|
-
return readDocument(docRef);
|
|
51
|
-
},
|
|
52
|
-
deleteSessions: async (shopId, sessionIds) => {
|
|
53
|
-
const collectionRef = shopCollection(shopId);
|
|
54
|
-
return Promise.all((0, index_js_1.ensureArray)(sessionIds).map((sessionId) => collectionRef.doc(sessionId).delete()));
|
|
55
|
-
},
|
|
56
|
-
findSessionIds: async (shopId) => {
|
|
57
|
-
// NOTE: empty rather than an error - this is the state on an initial install
|
|
58
|
-
if ((0, index_js_1.stringEmpty)(shopId)) {
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
const documents = await shopCollection(shopId).get();
|
|
62
|
-
return documents.docs.map((/** @type {any} */ { id }) => id);
|
|
63
|
-
},
|
|
64
|
-
loadState: async (shop) => ((0, index_js_1.stringEmpty)(shop)
|
|
65
|
-
? undefined
|
|
66
|
-
: readDocument(stateRef(shop))),
|
|
67
|
-
storeState: async (shop, state) => {
|
|
68
|
-
if ((0, index_js_1.stringEmpty)(shop)) {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
const docRef = stateRef(shop);
|
|
72
|
-
// the contract hands state over as `unknown` on purpose: it belongs to the consumer and is
|
|
73
|
-
// stored verbatim, so this cast is the implementation declining to look rather than a guess
|
|
74
|
-
await docRef.set(/** @type {any} */ (state));
|
|
75
|
-
return readDocument(docRef);
|
|
76
|
-
},
|
|
77
|
-
deleteState: async (shop) => ((0, index_js_1.stringEmpty)(shop)
|
|
78
|
-
? undefined
|
|
79
|
-
: stateRef(shop).delete()),
|
|
80
|
-
};
|
|
81
|
-
return storage;
|
|
82
|
-
};
|
|
83
|
-
exports.createFirestoreStorage = createFirestoreStorage;
|