@unisian/start 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.mjs CHANGED
@@ -81,6 +81,7 @@ const cachedQuery = (client, options) => {
81
81
  staleTime: "static"
82
82
  }).then(Option.some);
83
83
  };
84
+ const unobservedAndIdle = (cached) => cached.getObserversCount() === 0 && cached.state.fetchStatus === "idle";
84
85
  const command = (contract, serverFn, options) => {
85
86
  const { encodeInput, decodeOutput, call } = callerFor(contract, serverFn);
86
87
  return mutationOptions({
@@ -88,7 +89,13 @@ const command = (contract, serverFn, options) => {
88
89
  try {
89
90
  return decodeOutput(await call(encodeInput(input), options));
90
91
  } finally {
91
- await Promise.all(options.invalidates.map(({ name }) => client.invalidateQueries({ queryKey: [name] })));
92
+ await Promise.all(options.invalidates.map(({ name }) => {
93
+ client.removeQueries({
94
+ predicate: unobservedAndIdle,
95
+ queryKey: [name]
96
+ });
97
+ return client.invalidateQueries({ queryKey: [name] });
98
+ }));
92
99
  }
93
100
  },
94
101
  mutationKey: keyFor([contract.name], options)
package/dist/proxy.mjs CHANGED
@@ -7,6 +7,7 @@ import { RequestReference, logFailure } from "@unisian/effect-observability";
7
7
  import { LoggedInCustomer, ShopifyAdmin, ShopifyStorefront, StorefrontOperationRegistry, appProxyIdentity, shopifyLayer, verifyAppProxy } from "@unisian/shopify-auth";
8
8
  import * as Effect from "effect/Effect";
9
9
  import * as Layer from "effect/Layer";
10
+ import * as SchemaAST from "effect/SchemaAST";
10
11
  //#region src/proxy.ts
11
12
  const shopifyQueryKeys = /* @__PURE__ */ new Set([
12
13
  "logged_in_customer_id",
@@ -15,18 +16,28 @@ const shopifyQueryKeys = /* @__PURE__ */ new Set([
15
16
  "signature",
16
17
  "timestamp"
17
18
  ]);
18
- const fieldsOf = (entries) => {
19
- const fields = /* @__PURE__ */ new Map();
20
- for (const [key, value] of entries) if (!shopifyQueryKeys.has(key)) {
21
- const earlier = fields.get(key);
22
- fields.set(key, earlier === void 0 ? value : [...[earlier].flat(), value]);
19
+ const takesList = (ast) => SchemaAST.isArrays(ast) || SchemaAST.isUnion(ast) && ast.types.some(takesList);
20
+ const listKeysOf = (input) => {
21
+ const encoded = SchemaAST.toEncoded(input.ast);
22
+ return new Set(SchemaAST.isObjects(encoded) ? encoded.propertySignatures.filter((field) => takesList(field.type)).map(({ name }) => name) : []);
23
+ };
24
+ const fieldsOf = (entries, listKeys) => {
25
+ const singles = /* @__PURE__ */ new Map();
26
+ const lists = /* @__PURE__ */ new Map();
27
+ for (const [key, value] of entries) {
28
+ if (shopifyQueryKeys.has(key)) continue;
29
+ if (listKeys.has(key)) lists.set(key, [...lists.get(key) ?? [], value]);
30
+ else if (!singles.has(key)) singles.set(key, value);
23
31
  }
24
- return Object.fromEntries(fields);
32
+ return {
33
+ ...Object.fromEntries(singles),
34
+ ...Object.fromEntries(lists)
35
+ };
25
36
  };
26
37
  const decodeJsonBody = Schema.decodeUnknownEffect(Schema.Record(Schema.String, Schema.Json));
27
38
  const rejected = (cause) => new ProxyInputRejected({ cause });
28
39
  const isForm = (type) => type.startsWith("application/x-www-form-urlencoded") || type.startsWith("multipart/form-data");
29
- const bodyFields = (request) => {
40
+ const bodyFields = (request, listKeys) => {
30
41
  const type = request.headers.get("content-type") ?? "";
31
42
  if (type.startsWith("application/json")) return Effect.tryPromise({
32
43
  catch: rejected,
@@ -35,7 +46,7 @@ const bodyFields = (request) => {
35
46
  if (isForm(type)) return Effect.tryPromise({
36
47
  catch: rejected,
37
48
  try: () => request.formData()
38
- }).pipe(Effect.map((form) => fieldsOf(form.entries())));
49
+ }).pipe(Effect.map((form) => fieldsOf(form.entries(), listKeys)));
39
50
  return Effect.succeed({});
40
51
  };
41
52
  const buyerIp = (request) => {
@@ -65,6 +76,7 @@ const answerWith = (answer, output, encoded, fields, storefront) => {
65
76
  const loggedOutAnswer = (answer, fields, storefront) => answer.answer === "page" || answer.answer === "redirect" && !fetchedSave(answer, fields) ? proxyRedirect(storefront.login()) : proxyError("unauthorized", "Login required");
66
77
  const project = (config) => (contract, options, run) => {
67
78
  const decodeInput = Schema.decodeUnknownEffect(contract.input);
79
+ const listKeys = listKeysOf(contract.input);
68
80
  const encodeOutput = Schema.encodeEffect(Schema.toCodecJson(contract.output));
69
81
  const isFailure = Schema.is(contract.failure);
70
82
  const refuseWith = (storefront) => (failure) => options.refuse === void 0 ? Effect.die(failure) : Effect.succeed(options.refuse(failure, storefront));
@@ -73,9 +85,9 @@ const project = (config) => (contract, options, run) => {
73
85
  const layerFor = (proxy) => Layer.mergeAll(appProxyIdentity(proxy), ShopifyAdmin.layerForShop(proxy.shop), ShopifyStorefront.layerForShop(proxy.shop, buyerIp(request)), Layer.succeed(RequestReference, { reference: log.reference }), services ?? Layer.empty).pipe(Layer.orDie);
74
86
  const served = Effect.gen(function* serveProxy() {
75
87
  const proxy = yield* verifyAppProxy(request);
76
- const body = yield* bodyFields(request);
88
+ const body = yield* bodyFields(request, listKeys);
77
89
  const fields = {
78
- ...fieldsOf(new URL(request.url).searchParams),
90
+ ...fieldsOf(new URL(request.url).searchParams, listKeys),
79
91
  ...body,
80
92
  ...params
81
93
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unisian/start",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,10 +35,10 @@
35
35
  "react": "19.3.0",
36
36
  "react-dom": "19.3.0",
37
37
  "vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
38
- "@unisian/capability": "0.4.1",
39
- "@unisian/effect-observability": "0.4.1",
40
- "@unisian/shopify-auth": "0.4.1",
41
- "@unisian/shopify-sessions": "0.4.1"
38
+ "@unisian/capability": "0.4.3",
39
+ "@unisian/effect-observability": "0.4.3",
40
+ "@unisian/shopify-auth": "0.4.3",
41
+ "@unisian/shopify-sessions": "0.4.3"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@tanstack/react-query": "^5.104.1",
@@ -48,10 +48,10 @@
48
48
  "effect": "^4.0.2",
49
49
  "react": "^19.3.0",
50
50
  "react-dom": "^19.3.0",
51
- "@unisian/capability": "0.4.1",
52
- "@unisian/effect-observability": "0.4.1",
53
- "@unisian/shopify-auth": "0.4.1",
54
- "@unisian/shopify-sessions": "0.4.1"
51
+ "@unisian/capability": "0.4.3",
52
+ "@unisian/shopify-auth": "0.4.3",
53
+ "@unisian/shopify-sessions": "0.4.3",
54
+ "@unisian/effect-observability": "0.4.3"
55
55
  },
56
56
  "scripts": {}
57
57
  }