@plitzi/sdk-shared 0.33.2 → 0.34.1
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 +64 -0
- package/dist/actions/cron.d.ts +34 -0
- package/dist/actions/cron.mjs +72 -0
- package/dist/actions/index.d.ts +6 -0
- package/dist/actions/index.mjs +5 -0
- package/dist/actions/triggerParams.d.ts +41 -0
- package/dist/actions/triggerParams.mjs +40 -0
- package/dist/actions/triggers.d.ts +29 -0
- package/dist/actions/triggers.mjs +4 -0
- package/dist/actions/validateDocument.d.ts +23 -0
- package/dist/actions/validateDocument.mjs +267 -0
- package/dist/auth/failureChannel.d.ts +9 -4
- package/dist/auth/failureChannel.mjs +3 -2
- package/dist/authoring/builder.d.ts +51 -0
- package/dist/authoring/builder.mjs +29 -0
- package/dist/authoring/declare.d.ts +64 -0
- package/dist/authoring/declare.mjs +4 -0
- package/dist/authoring/elementCallbacks.d.ts +13 -0
- package/dist/authoring/elementCallbacks.mjs +71 -0
- package/dist/authoring/index.d.ts +21 -0
- package/dist/authoring/index.mjs +6 -0
- package/dist/authoring/paramSpec.d.ts +51 -0
- package/dist/authoring/paramSpec.mjs +40 -0
- package/dist/authoring/spaceCallbacks.d.ts +10 -0
- package/dist/authoring/spaceCallbacks.mjs +51 -0
- package/dist/builder/contexts/BuilderContext.d.ts +2 -4
- package/dist/dataSource/getBindingsDetails.mjs +1 -1
- package/dist/dataSource/helpers/getSourceName.d.ts +1 -3
- package/dist/dataSource/helpers/getSourceName.mjs +1 -1
- package/dist/dataSource/index.d.ts +2 -0
- package/dist/dataSource/index.mjs +6 -5
- package/dist/dataSource/resolveVariables.d.ts +22 -0
- package/dist/dataSource/resolveVariables.mjs +16 -0
- package/dist/dataSource/utility/index.mjs +15 -13
- package/dist/dataSource/utility/not.d.ts +11 -0
- package/dist/dataSource/utility/not.mjs +15 -0
- package/dist/devTools/debugCookie.d.ts +16 -0
- package/dist/devTools/debugCookie.mjs +7 -0
- package/dist/devTools/index.d.ts +6 -2
- package/dist/devTools/index.mjs +4 -2
- package/dist/devTools/interactionLog.d.ts +14 -0
- package/dist/devTools/interactionLog.mjs +4 -0
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.mjs +11 -9
- package/dist/helpers/reducerOrigin.d.ts +15 -0
- package/dist/helpers/reducerOrigin.mjs +4 -0
- package/dist/helpers/ruleEvaluator.d.ts +14 -0
- package/dist/helpers/ruleEvaluator.mjs +5 -0
- package/dist/helpers/twigWrapper/AST.d.ts +12 -1
- package/dist/helpers/twigWrapper/AST.mjs +0 -0
- package/dist/helpers/twigWrapper/Evaluator/Evaluator.mjs +7 -0
- package/dist/helpers/twigWrapper/Parser/Cursor.d.ts +7 -0
- package/dist/helpers/twigWrapper/Parser/Cursor.mjs +5 -0
- package/dist/helpers/twigWrapper/Parser/ExpressionParser.mjs +46 -8
- package/dist/helpers/twigWrapper/Parser/types.mjs +0 -0
- package/dist/helpers/twigWrapper/charClass.d.ts +7 -0
- package/dist/helpers/twigWrapper/charClass.mjs +16 -12
- package/dist/helpers/twigWrapper/tokens/tokenPatterns.mjs +2 -2
- package/dist/helpers/utils.d.ts +0 -2
- package/dist/helpers/utils.mjs +16 -19
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.mjs +4 -3
- package/dist/hooks/useFontHead.d.ts +3 -0
- package/dist/hooks/useFontHead.mjs +23 -0
- package/dist/hooks/usePlitziServiceContext.d.ts +3 -2
- package/dist/index.mjs +61 -45
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.mjs +2 -2
- package/dist/navigation/routes.d.ts +8 -0
- package/dist/navigation/routes.mjs +39 -39
- package/dist/network/graphql/builder/Mutations/Segment/SegmentAddMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/SegmentAddTemplateMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/SegmentUpdateMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentAddElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentCloneElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentMoveElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentRemoveElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentRenameElementMutation.d.ts +3 -0
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentRenameElementMutation.mjs +9 -0
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentUpdateElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Segment/space/elements/SegmentUpdateElementsMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceAddElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceAddTemplateMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceCloneElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceMoveElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceRemoveElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceRenameElementMutation.d.ts +5 -0
- package/dist/network/graphql/builder/Mutations/Space/SpaceRenameElementMutation.mjs +9 -0
- package/dist/network/graphql/builder/Mutations/Space/SpaceUpdateElementMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceUpdateElementsMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceUpdateMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/SpaceUpdateSchemaMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceAddActionMutation.d.ts +8 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceAddActionMutation.mjs +16 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceRemoveActionMutation.d.ts +4 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceRemoveActionMutation.mjs +16 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceRunActionMutation.d.ts +4 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceRunActionMutation.mjs +14 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceUpdateActionMutation.d.ts +4 -0
- package/dist/network/graphql/builder/Mutations/Space/actions/SpaceUpdateActionMutation.mjs +16 -0
- package/dist/network/graphql/builder/Mutations/Space/pages/SpaceAddPageMutation.mjs +2 -3
- package/dist/network/graphql/builder/Mutations/Space/pages/SpaceUpdatePageMutation.mjs +0 -1
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleAddFontMutation.d.ts +2 -0
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleAddFontMutation.mjs +11 -0
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleRemoveFontMutation.d.ts +2 -0
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleRemoveFontMutation.mjs +11 -0
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleUpdateFontMutation.d.ts +2 -0
- package/dist/network/graphql/builder/Mutations/Style/fonts/StyleUpdateFontMutation.mjs +11 -0
- package/dist/network/graphql/builder/Mutations/index.d.ts +24 -0
- package/dist/network/graphql/builder/Mutations/index.mjs +150 -132
- package/dist/network/graphql/builder/Queries/InitQuery.mjs +1 -2
- package/dist/network/graphql/builder/Queries/Segment/SegmentQuery.mjs +0 -1
- package/dist/network/graphql/builder/Queries/Segment/SegmentsQuery.mjs +0 -1
- package/dist/network/graphql/builder/Queries/Space/SpaceActionEventsQuery.d.ts +9 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceActionEventsQuery.mjs +30 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceActionTasksQuery.d.ts +6 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceActionTasksQuery.mjs +16 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceActionsQuery.d.ts +9 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceActionsQuery.mjs +25 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceCheckActionQuery.d.ts +6 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceCheckActionQuery.mjs +17 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceQuotaQuery.d.ts +30 -0
- package/dist/network/graphql/builder/Queries/Space/SpaceQuotaQuery.mjs +40 -0
- package/dist/network/graphql/builder/Queries/index.d.ts +16 -0
- package/dist/network/graphql/builder/Queries/index.mjs +24 -14
- package/dist/network/graphql/sdk/Queries/InitQuery.d.ts +4 -0
- package/dist/network/graphql/sdk/Queries/InitQuery.mjs +5 -2
- package/dist/network/graphql/sdk/Queries/Segment/SegmentQuery.mjs +0 -1
- package/dist/network/graphql/sdk/Queries/Segment/SegmentsQuery.mjs +0 -1
- package/dist/network/spaceEvents.d.ts +20 -1
- package/dist/network/spaceEvents.mjs +89 -74
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.mjs +2 -1
- package/dist/schema/serverElements.d.ts +16 -0
- package/dist/schema/serverElements.mjs +18 -0
- package/dist/server/actions/useActionsSync.d.ts +10 -0
- package/dist/server/actions/useActionsSync.mjs +7 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.mjs +5 -4
- package/dist/server/rsc/refreshRsc.d.ts +11 -1
- package/dist/server/rsc/refreshRsc.mjs +30 -12
- package/dist/server/rsc/useRscSync.mjs +20 -13
- package/dist/state/runtimeStatePersist.mjs +4 -3
- package/dist/store/actionRuns/actionRunsRecorder.d.ts +36 -0
- package/dist/store/actionRuns/actionRunsRecorder.mjs +39 -0
- package/dist/store/actionRuns/actionRunsStore.d.ts +16 -0
- package/dist/store/actionRuns/actionRunsStore.mjs +5 -0
- package/dist/store/actionRuns/index.d.ts +6 -0
- package/dist/store/actionRuns/index.mjs +4 -0
- package/dist/store/actionRuns/useActionRuns.d.ts +13 -0
- package/dist/store/actionRuns/useActionRuns.mjs +10 -0
- package/dist/store/index.d.ts +46 -45
- package/dist/store/index.mjs +6 -3
- package/dist/store/renderSettings.d.ts +3 -0
- package/dist/store/renderSettings.mjs +17 -5
- package/dist/store/tracing/tracingCollector.d.ts +1 -1
- package/dist/store/tracing/tracingCollector.mjs +37 -35
- package/dist/store/tracing/tracingStore.d.ts +13 -0
- package/dist/store/tracing/tracingStore.mjs +3 -3
- package/dist/style/fontAssets.d.ts +12 -0
- package/dist/style/fontAssets.mjs +18 -0
- package/dist/style/fontValidation.d.ts +8 -0
- package/dist/style/fontValidation.mjs +107 -0
- package/dist/style/fonts.d.ts +74 -0
- package/dist/style/fonts.mjs +198 -0
- package/dist/style/fontsFromCss.d.ts +27 -0
- package/dist/style/fontsFromCss.mjs +43 -0
- package/dist/style/index.d.ts +4 -0
- package/dist/style/index.mjs +5 -1
- package/dist/style/styleConstants.d.ts +2 -2
- package/dist/style/styleConstants.mjs +1 -0
- package/dist/theme/ThemeProvider.d.ts +36 -6
- package/dist/theme/ThemeProvider.mjs +49 -35
- package/dist/theme/ThemeScope.d.ts +16 -0
- package/dist/theme/ThemeScope.mjs +6 -0
- package/dist/theme/index.d.ts +7 -1
- package/dist/theme/index.mjs +6 -2
- package/dist/theme/themeCookie.d.ts +30 -0
- package/dist/theme/themeCookie.mjs +24 -0
- package/dist/theme/themeStore.d.ts +40 -0
- package/dist/theme/themeStore.mjs +17 -0
- package/dist/theme/useTheme.d.ts +29 -0
- package/dist/theme/useTheme.mjs +20 -0
- package/dist/types/ActionTypes.d.ts +396 -0
- package/dist/types/ActionTypes.mjs +0 -0
- package/dist/types/AuthTypes.d.ts +23 -2
- package/dist/types/BuilderTypes.d.ts +0 -12
- package/dist/types/CommonTypes.d.ts +13 -0
- package/dist/types/DevToolsTypes.d.ts +57 -14
- package/dist/types/EventBridgeTypes.d.ts +1 -1
- package/dist/types/InteractionTypes.d.ts +23 -3
- package/dist/types/PluginTypes.d.ts +0 -3
- package/dist/types/SchemaTypes.d.ts +29 -4
- package/dist/types/ServerTypes.d.ts +390 -46
- package/dist/types/SpaceTypes.d.ts +16 -0
- package/dist/types/StoreTypes.d.ts +181 -3
- package/dist/types/StyleTypes.d.ts +83 -4
- package/dist/types/TemplateTypes.d.ts +20 -0
- package/dist/types/TemplateTypes.mjs +0 -0
- package/dist/types/ThemeTypes.d.ts +28 -1
- package/dist/types/index.d.ts +2 -0
- package/eslint.config.mjs +2 -0
- package/package.json +244 -29
- package/vite.config.ts +27 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# @plitzi/sdk-shared
|
|
2
2
|
|
|
3
|
+
## 0.34.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- v0.34.1
|
|
8
|
+
|
|
9
|
+
## 0.34.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 5aceda0: `authorSpace` returns test handles, and every element carries its id in the DOM.
|
|
14
|
+
|
|
15
|
+
An end-to-end suite had nothing stable to address a rendered element by: a class is a styling decision that
|
|
16
|
+
changes with the design, a text match breaks when the copy is edited, and an `nth-child` chain is invalidated by
|
|
17
|
+
inserting a section above. What does not move is the element's id — which is also its name, chosen by whoever
|
|
18
|
+
authored it and unique across the document.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const { schema, style, handles } = authorSpace(spec);
|
|
22
|
+
const el = locate(page, handles);
|
|
23
|
+
|
|
24
|
+
await expect(el('hero-title')).toBeVisible();
|
|
25
|
+
await page.goto(handles.page('pricing').path);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Elements now render `data-plitzi-el="<id>"`. It ships by default — the ids are already in the page, since the
|
|
29
|
+
schema the browser hydrates from carries every one of them — and a deployment turns it off with
|
|
30
|
+
`render.testAttributes: false`.
|
|
31
|
+
|
|
32
|
+
Each handle reports whether the AUTHOR wrote the id or authoring derived a positional `<type>-<n>`, which is
|
|
33
|
+
what makes one generic assertion possible for any space: everything a space names must be on screen. A name that
|
|
34
|
+
does not exist throws at author time with a suggestion, rather than resolving to an empty locator at test time.
|
|
35
|
+
|
|
36
|
+
- v0.34.0
|
|
37
|
+
- 5aceda0: Draft previews you can iterate against, and a `DraftStore` contract that says so.
|
|
38
|
+
|
|
39
|
+
A preview token was one-shot: spent by the render that used it. That is right for a capture and wrong for a
|
|
40
|
+
person — reloading showed the saved space again, so "look at the change, adjust it, look again" meant minting a
|
|
41
|
+
new token for every look. `POST /__preview` now takes `mode: 'session'`, which mints a token that stays
|
|
42
|
+
resolvable until it expires (`preview.sessionTtlMs`, 15 minutes by default) or until `POST /__preview/end` ends
|
|
43
|
+
it. The token is remembered in an `HttpOnly` cookie on the first render, so the draft follows a navigation —
|
|
44
|
+
the page after a link carries no query parameter.
|
|
45
|
+
|
|
46
|
+
A draft render, either mode, is never cached, never metered and answers `Cache-Control: no-store` plus
|
|
47
|
+
`X-Robots-Tag: noindex`. Data refreshes (`/_rsc`) made from inside a session are excluded from metering and
|
|
48
|
+
caching too — without that, an open preview tab would be billed as live traffic.
|
|
49
|
+
|
|
50
|
+
**Breaking, for anyone who implements `DraftStore`** (a shared store for a multi-replica deployment). The
|
|
51
|
+
default in-memory store is unaffected; a custom one needs three changes:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// before
|
|
55
|
+
put(token, data, ttlMs)
|
|
56
|
+
take(token): OfflineDataRaw | undefined
|
|
57
|
+
|
|
58
|
+
// after
|
|
59
|
+
put(token, data, { ttlMs, reusable }) // `reusable` is a session; absent is one-shot
|
|
60
|
+
take(token): { data, reusable } | undefined // consume unless reusable — and say which it was
|
|
61
|
+
drop(token) // end a session before its TTL
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`take` reports which kind it resolved because the render that resolves a session is the one that has to remember
|
|
65
|
+
it for the rest of the visit, and only the store knows whether the token survived the read.
|
|
66
|
+
|
|
3
67
|
## 0.33.2
|
|
4
68
|
|
|
5
69
|
### Patch Changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type CronExpression = Set<number>[];
|
|
2
|
+
/** Parses an expression, or undefined when it is not one this understands — which the validator reports rather
|
|
3
|
+
* than letting a silently-never-firing schedule sit in a document. */
|
|
4
|
+
export declare const parseCron: (expression: string) => CronExpression | undefined;
|
|
5
|
+
/** The five numbers a cron expression is matched against — a wall clock, in whatever zone it was read in. */
|
|
6
|
+
type WallClock = {
|
|
7
|
+
minute: number;
|
|
8
|
+
hour: number;
|
|
9
|
+
day: number;
|
|
10
|
+
month: number;
|
|
11
|
+
weekday: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The same instant, as the clock on a wall in `timeZone` reads it.
|
|
15
|
+
*
|
|
16
|
+
* Through `Intl` rather than an offset table, because an offset is not a constant: "9am in Santiago" is a
|
|
17
|
+
* different instant in January and in July, and a schedule that means the working day has to follow the change.
|
|
18
|
+
* `hourCycle: 'h23'` matters — the other cycles render midnight as 24, which cron has no hour for.
|
|
19
|
+
*
|
|
20
|
+
* An unknown zone answers `undefined` rather than falling back to UTC. Falling back is what this whole change is
|
|
21
|
+
* about: a schedule that fires at the wrong hour and says nothing.
|
|
22
|
+
*/
|
|
23
|
+
export declare const zonedClock: (at: Date, timeZone: string) => WallClock | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Whether an expression fires at this minute — in `timeZone` when one is named, in UTC when none is.
|
|
26
|
+
*
|
|
27
|
+
* Day-of-month and day-of-week are OR'd when both are restricted, which is the rule every cron implementation
|
|
28
|
+
* follows and the one that surprises people who expect AND — `0 0 1 * 1` fires on the first of the month AND on
|
|
29
|
+
* every Monday.
|
|
30
|
+
*/
|
|
31
|
+
export declare const cronMatches: (expression: string, at: Date, timeZone?: string) => boolean;
|
|
32
|
+
/** Whether `Intl` knows this zone. The validator asks so an author hears about a typo in the editor. */
|
|
33
|
+
export declare const isKnownTimeZone: (timeZone: string) => boolean;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/actions/cron.ts
|
|
2
|
+
var e = [
|
|
3
|
+
[0, 59],
|
|
4
|
+
[0, 23],
|
|
5
|
+
[1, 31],
|
|
6
|
+
[1, 12],
|
|
7
|
+
[0, 6]
|
|
8
|
+
], t = (e, [t, n]) => {
|
|
9
|
+
let r = /* @__PURE__ */ new Set();
|
|
10
|
+
for (let i of e.split(",")) {
|
|
11
|
+
let [e, a] = i.split("/"), o = a === void 0 ? 1 : Number.parseInt(a, 10);
|
|
12
|
+
if (!Number.isFinite(o) || o < 1) return;
|
|
13
|
+
let s = t, c = n;
|
|
14
|
+
if (e !== void 0 && e !== "*" && e !== "") {
|
|
15
|
+
let [r, i] = e.split("-");
|
|
16
|
+
if (s = Number.parseInt(r ?? "", 10), c = i === void 0 ? s : Number.parseInt(i, 10), !Number.isFinite(s) || !Number.isFinite(c) || s < t || c > n || s > c) return;
|
|
17
|
+
}
|
|
18
|
+
for (let e = s; e <= c; e += o) r.add(e);
|
|
19
|
+
}
|
|
20
|
+
return r;
|
|
21
|
+
}, n = (n) => {
|
|
22
|
+
let r = n.trim().split(/\s+/);
|
|
23
|
+
if (r.length !== 5) return;
|
|
24
|
+
let i = r.map((n, r) => t(n, e[r]));
|
|
25
|
+
return i.every((e) => e !== void 0) ? i : void 0;
|
|
26
|
+
}, r = [
|
|
27
|
+
"Sun",
|
|
28
|
+
"Mon",
|
|
29
|
+
"Tue",
|
|
30
|
+
"Wed",
|
|
31
|
+
"Thu",
|
|
32
|
+
"Fri",
|
|
33
|
+
"Sat"
|
|
34
|
+
], i = (e) => ({
|
|
35
|
+
minute: e.getUTCMinutes(),
|
|
36
|
+
hour: e.getUTCHours(),
|
|
37
|
+
day: e.getUTCDate(),
|
|
38
|
+
month: e.getUTCMonth() + 1,
|
|
39
|
+
weekday: e.getUTCDay()
|
|
40
|
+
}), a = (e, t) => {
|
|
41
|
+
try {
|
|
42
|
+
let n = new Intl.DateTimeFormat("en-US", {
|
|
43
|
+
timeZone: t,
|
|
44
|
+
hourCycle: "h23",
|
|
45
|
+
month: "numeric",
|
|
46
|
+
day: "numeric",
|
|
47
|
+
hour: "numeric",
|
|
48
|
+
minute: "numeric",
|
|
49
|
+
weekday: "short"
|
|
50
|
+
}).formatToParts(e), i = (e) => n.find((t) => t.type === e)?.value ?? "", a = r.indexOf(i("weekday")), o = {
|
|
51
|
+
minute: Number(i("minute")),
|
|
52
|
+
hour: Number(i("hour")),
|
|
53
|
+
day: Number(i("day")),
|
|
54
|
+
month: Number(i("month")),
|
|
55
|
+
weekday: a
|
|
56
|
+
};
|
|
57
|
+
return a >= 0 && Object.values(o).every(Number.isFinite) ? o : void 0;
|
|
58
|
+
} catch {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}, o = (e, t, r) => {
|
|
62
|
+
let o = n(e);
|
|
63
|
+
if (!o) return !1;
|
|
64
|
+
let s = r ? a(t, r) : i(t);
|
|
65
|
+
if (!s) return !1;
|
|
66
|
+
let [c, l, u, d, f] = o;
|
|
67
|
+
if (!c.has(s.minute) || !l.has(s.hour) || !d.has(s.month)) return !1;
|
|
68
|
+
let p = u.size !== 31, m = f.size !== 7, h = u.has(s.day), g = f.has(s.weekday);
|
|
69
|
+
return p && m ? h || g : h && g;
|
|
70
|
+
}, s = (e) => a(/* @__PURE__ */ new Date(), e) !== void 0;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { o as cronMatches, s as isKnownTimeZone, n as parseCron, a as zonedClock };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { cronMatches, isKnownTimeZone, parseCron, zonedClock } from './cron';
|
|
2
|
+
export { triggerAccess, triggerCacheMs, triggerHasStaleVerify, triggerInput, triggerVerify } from './triggerParams';
|
|
3
|
+
export { actionName, actionTriggers, isActionEnabled } from './triggers';
|
|
4
|
+
export { validateActionDocument } from './validateDocument';
|
|
5
|
+
export type { CronExpression } from './cron';
|
|
6
|
+
export type { ActionDocumentIssue, ActionDocumentReport } from './validateDocument';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { cronMatches as e, isKnownTimeZone as t, parseCron as n, zonedClock as r } from "./cron.mjs";
|
|
2
|
+
import { triggerAccess as i, triggerCacheMs as a, triggerHasStaleVerify as o, triggerInput as s, triggerVerify as c } from "./triggerParams.mjs";
|
|
3
|
+
import { actionName as l, actionTriggers as u, isActionEnabled as d } from "./triggers.mjs";
|
|
4
|
+
import { validateActionDocument as f } from "./validateDocument.mjs";
|
|
5
|
+
export { l as actionName, u as actionTriggers, e as cronMatches, d as isActionEnabled, t as isKnownTimeZone, n as parseCron, i as triggerAccess, a as triggerCacheMs, o as triggerHasStaleVerify, s as triggerInput, c as triggerVerify, f as validateActionDocument, r as zonedClock };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ActionAccess, ActionField, ActionTriggerParams, ActionWebhookVerification } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Who may start a run this way.
|
|
4
|
+
*
|
|
5
|
+
* `undefined` is a trigger that states no rule, which is refused rather than guessed at — every guess is either a
|
|
6
|
+
* lock-out or a hole. A `schedule` has no caller and states none, and the runner does not ask.
|
|
7
|
+
*/
|
|
8
|
+
export declare const triggerAccess: (params: ActionTriggerParams) => ActionAccess | undefined;
|
|
9
|
+
/** What a caller may send through this way in. An unparseable map reads as no contract at all, which drops every key. */
|
|
10
|
+
export declare const triggerInput: (params: ActionTriggerParams) => Record<string, ActionField>;
|
|
11
|
+
/** How an inbound webhook proves itself, or nothing — which is an endpoint anyone who learns the URL can start. */
|
|
12
|
+
/**
|
|
13
|
+
* How this webhook proves who is calling it — assembled from the trigger's own fields, not parsed out of a blob.
|
|
14
|
+
*
|
|
15
|
+
* **Naming the credential is what turns it on.** Everything else has a working default, so there is no state
|
|
16
|
+
* between "unsigned" and "verified" for an author to get stuck in: it was a JSON object with an empty
|
|
17
|
+
* `credential` in it, which the editor offered by default and the validator then refused, so picking the webhook
|
|
18
|
+
* trigger produced an error before anybody had typed anything.
|
|
19
|
+
*/
|
|
20
|
+
export declare const triggerVerify: (params: ActionTriggerParams) => ActionWebhookVerification | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Whether this trigger carries a signature check that USED TO VERIFY something and no longer does.
|
|
23
|
+
*
|
|
24
|
+
* A guard, not a compatibility layer: nothing here interprets the old shape, and the only question it answers is
|
|
25
|
+
* whether ignoring it would fail OPEN. A stored `verify: '{…}'` that named a credential was a protected endpoint;
|
|
26
|
+
* read as "unsigned" it becomes a public one with nothing in the document changing, which is the one degradation
|
|
27
|
+
* that must never happen by omission — so it is refused until somebody moves it across.
|
|
28
|
+
*
|
|
29
|
+
* A leftover blob that named NO credential verified nothing to begin with. It is not a downgrade, it is a field
|
|
30
|
+
* the editor used to offer filled in with a default and never completed — and treating it as an error would be an
|
|
31
|
+
* error about something the editor no longer shows, on a webhook that was always unsigned. That one is simply
|
|
32
|
+
* unsigned, and warned about like any other.
|
|
33
|
+
*/
|
|
34
|
+
export declare const triggerHasStaleVerify: (params: ActionTriggerParams) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* How long a `render` answer may be reused, in milliseconds.
|
|
37
|
+
*
|
|
38
|
+
* Read through here rather than parsed at the call site so the validator and the runtime agree on what an
|
|
39
|
+
* unparseable value means: nothing, which is the same as not caching — never an accidental eternity.
|
|
40
|
+
*/
|
|
41
|
+
export declare const triggerCacheMs: (params: ActionTriggerParams) => number;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/actions/triggerParams.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (typeof e == "string" && e.trim() !== "") try {
|
|
4
|
+
return JSON.parse(e);
|
|
5
|
+
} catch {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
}, t = (e) => typeof e == "object" && !!e && !Array.isArray(e), n = (e) => {
|
|
9
|
+
let { access: t } = e;
|
|
10
|
+
if (t === "public" || t === "session") return { mode: t };
|
|
11
|
+
if (t === "role") return {
|
|
12
|
+
mode: "role",
|
|
13
|
+
permissions: (e.permissions ?? "").split(",").map((e) => e.trim()).filter(Boolean)
|
|
14
|
+
};
|
|
15
|
+
}, r = (n) => {
|
|
16
|
+
let r = e(n.input);
|
|
17
|
+
return t(r) ? r : {};
|
|
18
|
+
}, i = (e) => {
|
|
19
|
+
let t = e.signatureCredential?.trim();
|
|
20
|
+
if (!t) return;
|
|
21
|
+
let n = e.signatureSecretField?.trim(), r = e.signatureTimestampHeader?.trim(), i = Number.parseFloat(e.signatureToleranceSeconds ?? "");
|
|
22
|
+
return {
|
|
23
|
+
type: "hmac",
|
|
24
|
+
header: e.signatureHeader?.trim() || "x-signature",
|
|
25
|
+
algorithm: e.signatureAlgorithm?.trim() === "sha1" ? "sha1" : "sha256",
|
|
26
|
+
credential: t,
|
|
27
|
+
...n ? { secretField: n } : {},
|
|
28
|
+
...r ? { timestampHeader: r } : {},
|
|
29
|
+
...Number.isFinite(i) && i > 0 ? { toleranceSeconds: Math.round(i) } : {}
|
|
30
|
+
};
|
|
31
|
+
}, a = (n) => {
|
|
32
|
+
if (n.signatureCredential?.trim()) return !1;
|
|
33
|
+
let r = e(n.verify);
|
|
34
|
+
return t(r) && typeof r.credential == "string" && r.credential.trim() !== "";
|
|
35
|
+
}, o = (e) => {
|
|
36
|
+
let t = Number.parseFloat(e.cacheSeconds ?? "");
|
|
37
|
+
return Number.isFinite(t) && t > 0 ? Math.round(t * 1e3) : 0;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { n as triggerAccess, o as triggerCacheMs, a as triggerHasStaleVerify, r as triggerInput, i as triggerVerify };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ActionDocument, ElementInteraction } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* The ways into an action, read off the flow.
|
|
4
|
+
*
|
|
5
|
+
* A way in is a trigger STEP, so this is the only place that has to know it — the builder's list, the MCP summary
|
|
6
|
+
* and the schedule sweep all ask the same question of the same document and cannot answer it differently.
|
|
7
|
+
*/
|
|
8
|
+
export declare const actionTriggers: (document: ActionDocument) => ElementInteraction[];
|
|
9
|
+
/**
|
|
10
|
+
* Whether this action can run at all: whether ANY way into it is switched on.
|
|
11
|
+
*
|
|
12
|
+
* DERIVED, never stored. The switch belongs to the trigger — one per way in — and an action-level copy of it was a
|
|
13
|
+
* second answer to the same question: the builder computed it from the steps, the store overwrote it from its own
|
|
14
|
+
* column, and the two could disagree with nothing to say which won. A store that keeps a column for it (to index
|
|
15
|
+
* the schedule sweep, say) writes what this returns, and reads it back as a cache rather than as a decision.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isActionEnabled: (document: ActionDocument) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* What to call this action, read off the flow that starts it.
|
|
20
|
+
*
|
|
21
|
+
* The trigger step is already named — the editor puts an editable title on every node — so a field beside the flow
|
|
22
|
+
* asked the author to name the same thing twice, and left two names with no rule for which one anybody meant. The
|
|
23
|
+
* FIRST trigger wins because it is the one the list and the picker show; an action with several ways in is still
|
|
24
|
+
* one action, and naming it after the way most callers reach it is the honest summary.
|
|
25
|
+
*
|
|
26
|
+
* Falls back to whatever the document already carries, so a document written before this — or by a caller that
|
|
27
|
+
* names it directly, like the authoring API — keeps the name it was given.
|
|
28
|
+
*/
|
|
29
|
+
export declare const actionName: (document: ActionDocument) => string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//#region src/actions/triggers.ts
|
|
2
|
+
var e = (e) => Object.values(e.nodes).filter((e) => e.type === "trigger"), t = (t) => e(t).some((e) => e.enabled), n = (t) => e(t).find((e) => e.title.trim() !== "")?.title.trim() ?? t.name;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { n as actionName, e as actionTriggers, t as isActionEnabled };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one server-action validator.
|
|
3
|
+
*
|
|
4
|
+
* Three places decide whether a document is fit to store — the builder panel, the MCP write ops and the GraphQL
|
|
5
|
+
* mutation that persists it — and a document is only ever wrong in one way, so the rules live here instead of
|
|
6
|
+
* being restated (and drifting) at each entry point. The input is `unknown` because the server runs it last, on
|
|
7
|
+
* whatever JSON actually arrived: it validates a document, it does not assume one.
|
|
8
|
+
*
|
|
9
|
+
* Errors are what the runner cannot recover from at request time; warnings are what will run but probably does
|
|
10
|
+
* not do what the author meant.
|
|
11
|
+
*/
|
|
12
|
+
export type ActionDocumentIssue = {
|
|
13
|
+
/** Dotted path into the document, e.g. `nodes.send.action`. */
|
|
14
|
+
path: string;
|
|
15
|
+
message: string;
|
|
16
|
+
hint?: string;
|
|
17
|
+
};
|
|
18
|
+
export type ActionDocumentReport = {
|
|
19
|
+
valid: boolean;
|
|
20
|
+
errors: ActionDocumentIssue[];
|
|
21
|
+
warnings: ActionDocumentIssue[];
|
|
22
|
+
};
|
|
23
|
+
export declare const validateActionDocument: (document: unknown) => ActionDocumentReport;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { isKnownTimeZone as e, parseCron as t } from "./cron.mjs";
|
|
2
|
+
import { triggerAccess as n, triggerHasStaleVerify as r, triggerVerify as i } from "./triggerParams.mjs";
|
|
3
|
+
//#region src/actions/validateDocument.ts
|
|
4
|
+
var a = [
|
|
5
|
+
"text",
|
|
6
|
+
"number",
|
|
7
|
+
"boolean",
|
|
8
|
+
"date",
|
|
9
|
+
"json",
|
|
10
|
+
"file"
|
|
11
|
+
], o = [
|
|
12
|
+
"public",
|
|
13
|
+
"session",
|
|
14
|
+
"role"
|
|
15
|
+
], s = [
|
|
16
|
+
"call",
|
|
17
|
+
"webhook",
|
|
18
|
+
"schedule",
|
|
19
|
+
"render",
|
|
20
|
+
"custom"
|
|
21
|
+
], c = ["sha256", "sha1"], l = /* @__PURE__ */ new Set([
|
|
22
|
+
"input",
|
|
23
|
+
"user",
|
|
24
|
+
"spaceId",
|
|
25
|
+
"environment",
|
|
26
|
+
"trigger",
|
|
27
|
+
"runId"
|
|
28
|
+
]), u = /^[a-z][a-zA-Z0-9]*\.[a-z][a-zA-Z0-9]*$/, d = (e) => typeof e == "object" && !!e && !Array.isArray(e), f = (e) => typeof e == "string" && e.trim() !== "", p = (e) => {
|
|
29
|
+
try {
|
|
30
|
+
let t = JSON.parse(e);
|
|
31
|
+
return d(t) ? t : void 0;
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}, m = (e, t, n) => {
|
|
36
|
+
if (e !== void 0) {
|
|
37
|
+
if (!d(e)) {
|
|
38
|
+
n.push({
|
|
39
|
+
path: t,
|
|
40
|
+
message: "must be an object of field definitions"
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
Object.entries(e).forEach(([e, r]) => {
|
|
45
|
+
if (!d(r) || !f(r.type)) {
|
|
46
|
+
n.push({
|
|
47
|
+
path: `${t}.${e}`,
|
|
48
|
+
message: "must declare a type"
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
a.includes(r.type) || n.push({
|
|
53
|
+
path: `${t}.${e}.type`,
|
|
54
|
+
message: `unknown field type "${r.type}"`,
|
|
55
|
+
hint: `one of ${a.join(", ")}`
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}, h = (a, l, u, h) => {
|
|
60
|
+
let g = `nodes.${a}`, _ = l.action;
|
|
61
|
+
if (!f(_) || !s.includes(_)) {
|
|
62
|
+
u.push({
|
|
63
|
+
path: `${g}.action`,
|
|
64
|
+
message: `"${String(_)}" is not a way an action can be started`,
|
|
65
|
+
hint: `one of ${s.join(", ")}`
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
let v = d(l.params) ? l.params : {};
|
|
70
|
+
if (f(v.input)) {
|
|
71
|
+
let e = p(v.input);
|
|
72
|
+
e === void 0 ? u.push({
|
|
73
|
+
path: `${g}.params.input`,
|
|
74
|
+
message: "is not valid JSON"
|
|
75
|
+
}) : m(e, `${g}.params.input`, u);
|
|
76
|
+
}
|
|
77
|
+
if (_ !== "schedule") {
|
|
78
|
+
if (!f(v.access) || !o.includes(v.access)) u.push({
|
|
79
|
+
path: `${g}.params.access`,
|
|
80
|
+
message: "must say who may start a run this way",
|
|
81
|
+
hint: `one of ${o.join(", ")}`
|
|
82
|
+
});
|
|
83
|
+
else if (v.access === "role") {
|
|
84
|
+
let e = n(v);
|
|
85
|
+
e?.mode === "role" && e.permissions.length === 0 && u.push({
|
|
86
|
+
path: `${g}.params.permissions`,
|
|
87
|
+
message: "role access must name at least one permission"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (_ === "schedule" && (f(v.cron) ? t(v.cron) || u.push({
|
|
92
|
+
path: `${g}.params.cron`,
|
|
93
|
+
message: `"${v.cron}" is not an expression this server can read, so it would never fire`,
|
|
94
|
+
hint: "five fields — minute hour day-of-month month day-of-week — with *, lists, ranges and steps"
|
|
95
|
+
}) : u.push({
|
|
96
|
+
path: `${g}.params.cron`,
|
|
97
|
+
message: "a scheduled trigger needs a cron expression"
|
|
98
|
+
}), f(v.timezone) && !e(v.timezone) && u.push({
|
|
99
|
+
path: `${g}.params.timezone`,
|
|
100
|
+
message: `"${v.timezone}" is not a time zone this server knows, so the schedule would never fire`,
|
|
101
|
+
hint: "an IANA name like America/Santiago or Europe/Madrid — leave it empty for UTC"
|
|
102
|
+
})), f(v.cacheSeconds)) {
|
|
103
|
+
let e = Number.parseFloat(v.cacheSeconds);
|
|
104
|
+
!Number.isFinite(e) || e < 0 ? u.push({
|
|
105
|
+
path: `${g}.params.cacheSeconds`,
|
|
106
|
+
message: "must be a number of seconds, or left empty"
|
|
107
|
+
}) : _ !== "render" && h.push({
|
|
108
|
+
path: `${g}.params.cacheSeconds`,
|
|
109
|
+
message: `a "${_}" trigger is never answered from a cache`,
|
|
110
|
+
hint: "reuse only applies to a render, where the same page is built for one visitor after another"
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
_ === "custom" && !f(v.name) && u.push({
|
|
114
|
+
path: `${g}.params.name`,
|
|
115
|
+
message: "a custom trigger needs a name to be mounted under"
|
|
116
|
+
}), _ === "webhook" && (r(v) && u.push({
|
|
117
|
+
path: `${g}.params.signatureCredential`,
|
|
118
|
+
message: "this signature check is in a format nothing reads any more, so the webhook is unverified",
|
|
119
|
+
hint: "name the credential holding the signing secret in \"Signing secret\", and its header beside it"
|
|
120
|
+
}), i(v) || h.push({
|
|
121
|
+
path: `${g}.params.signatureCredential`,
|
|
122
|
+
message: "this webhook accepts unsigned requests",
|
|
123
|
+
hint: "name the credential holding the signing secret, and only the sender you expect can start a run"
|
|
124
|
+
}), f(v.signatureAlgorithm) && !c.includes(v.signatureAlgorithm) && h.push({
|
|
125
|
+
path: `${g}.params.signatureAlgorithm`,
|
|
126
|
+
message: `"${v.signatureAlgorithm}" is not an algorithm this server signs with, so sha256 is used`,
|
|
127
|
+
hint: `one of ${c.join(", ")}`
|
|
128
|
+
}), f(v.signatureToleranceSeconds) && !f(v.signatureTimestampHeader) && h.push({
|
|
129
|
+
path: `${g}.params.signatureToleranceSeconds`,
|
|
130
|
+
message: "a tolerance with no timestamp header expires nothing",
|
|
131
|
+
hint: "name the header the sender puts the signing time in, or drop the tolerance"
|
|
132
|
+
})), _ === "call" && v.access === "public" && h.push({
|
|
133
|
+
path: `${g}.params.access`,
|
|
134
|
+
message: "anyone can run this action, including signed-out visitors",
|
|
135
|
+
hint: "use session access unless the page needs it before anyone signs in"
|
|
136
|
+
});
|
|
137
|
+
}, g = (e, t, n, r) => {
|
|
138
|
+
if (!d(e)) {
|
|
139
|
+
n.push({
|
|
140
|
+
path: "nodes",
|
|
141
|
+
message: "must be an object of steps"
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let i = Object.entries(e), a = i.filter(([, e]) => d(e) && e.type === "trigger");
|
|
146
|
+
a.length === 0 && n.push({
|
|
147
|
+
path: "nodes",
|
|
148
|
+
message: "this action has no way in",
|
|
149
|
+
hint: "add a trigger step — call, webhook, schedule, render or custom"
|
|
150
|
+
});
|
|
151
|
+
let o = /* @__PURE__ */ new Map();
|
|
152
|
+
a.forEach(([e, t]) => {
|
|
153
|
+
f(t.action) && o.set(t.action, [...o.get(t.action) ?? [], e]);
|
|
154
|
+
}), o.forEach((e, t) => {
|
|
155
|
+
e.length > 1 && n.push({
|
|
156
|
+
path: `nodes.${e[1]}`,
|
|
157
|
+
message: `this action has ${e.length} "${t}" triggers`,
|
|
158
|
+
hint: "one step per way in — a second flow starts from a different kind of trigger"
|
|
159
|
+
});
|
|
160
|
+
}), i.forEach(([t, i]) => {
|
|
161
|
+
let a = `nodes.${t}`;
|
|
162
|
+
if (!d(i)) {
|
|
163
|
+
n.push({
|
|
164
|
+
path: a,
|
|
165
|
+
message: "must be an object"
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (i.type === "trigger") {
|
|
170
|
+
h(t, i, n, r);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (i.type !== "task") {
|
|
174
|
+
n.push({
|
|
175
|
+
path: `${a}.type`,
|
|
176
|
+
message: `"${String(i.type)}" steps run in the browser and cannot run on the server`,
|
|
177
|
+
hint: "a server action is made of task steps"
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!f(i.action) || !u.test(i.action)) {
|
|
182
|
+
n.push({
|
|
183
|
+
path: `${a}.action`,
|
|
184
|
+
message: "must name a task as <namespace>.<action>",
|
|
185
|
+
hint: "for example flow.output or http.request"
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
f(i.afterNode) && !Object.hasOwn(e, i.afterNode) && n.push({
|
|
190
|
+
path: `${a}.afterNode`,
|
|
191
|
+
message: `points at "${i.afterNode}", which is not a step here`
|
|
192
|
+
});
|
|
193
|
+
}), i.forEach(([e]) => {
|
|
194
|
+
l.has(e) && n.push({
|
|
195
|
+
path: `nodes.${e}`,
|
|
196
|
+
message: `"${e}" is what the run itself publishes in the flow scope, so a step may not take the name`,
|
|
197
|
+
hint: `rename the step — every later step reads {{ ${e} }} expecting the run's own value`
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
let s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set();
|
|
201
|
+
a.forEach(([t]) => {
|
|
202
|
+
let n = /* @__PURE__ */ new Set(), r = t;
|
|
203
|
+
for (; r;) {
|
|
204
|
+
if (n.has(r)) {
|
|
205
|
+
c.add(r);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
n.add(r), s.add(r);
|
|
209
|
+
let t = e[r];
|
|
210
|
+
r = f(t?.afterNode) ? t.afterNode : "";
|
|
211
|
+
}
|
|
212
|
+
}), c.forEach((e) => {
|
|
213
|
+
n.push({
|
|
214
|
+
path: `nodes.${e}`,
|
|
215
|
+
message: "this step is reached again by its own chain, so the flow never ends",
|
|
216
|
+
hint: "break the `afterNode` chain that comes back to it"
|
|
217
|
+
});
|
|
218
|
+
}), i.forEach(([e]) => {
|
|
219
|
+
s.has(e) || r.push({
|
|
220
|
+
path: `nodes.${e}`,
|
|
221
|
+
message: "no trigger reaches this step, so it never runs",
|
|
222
|
+
hint: "chain it with `afterNode` from a trigger, or delete it"
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
let p = i.filter(([, e]) => d(e) && e.action === "flow.output");
|
|
226
|
+
for (let [t, n] of p) f(n.afterNode) && Object.hasOwn(e, n.afterNode) && r.push({
|
|
227
|
+
path: `nodes.${t}.afterNode`,
|
|
228
|
+
message: "the output step is not the last one, so the steps after it run for nothing",
|
|
229
|
+
hint: "move flow.output to the end of the flow"
|
|
230
|
+
});
|
|
231
|
+
p.length === 0 && d(t) && Object.keys(t).length > 0 && r.push({
|
|
232
|
+
path: "nodes",
|
|
233
|
+
message: "this action is expected to answer values but no step names any",
|
|
234
|
+
hint: "add a flow.output step at the end naming what the caller should get"
|
|
235
|
+
});
|
|
236
|
+
}, _ = /\{\{\s*credential\./, v = (e, t) => {
|
|
237
|
+
Object.entries(e).forEach(([e, n]) => {
|
|
238
|
+
if (!d(n) || !d(n.params)) return;
|
|
239
|
+
let r = f(n.params.credential) ? n.params.credential : "";
|
|
240
|
+
Object.entries(n.params).forEach(([n, i]) => {
|
|
241
|
+
typeof i == "string" && _.test(i) && r === "" && t.push({
|
|
242
|
+
path: `nodes.${e}.params.${n}`,
|
|
243
|
+
message: "this step reads a credential it did not ask for, so the token resolves to nothing",
|
|
244
|
+
hint: "set the step’s `credential` to the identifier it should use"
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}, y = (e) => {
|
|
249
|
+
let t = [], n = [];
|
|
250
|
+
return d(e) ? (f(e.name) || t.push({
|
|
251
|
+
path: "name",
|
|
252
|
+
message: "must have a name"
|
|
253
|
+
}), m(e.output, "output", t), g(e.nodes, e.output, t, n), v(d(e.nodes) ? e.nodes : {}, n), {
|
|
254
|
+
valid: t.length === 0,
|
|
255
|
+
errors: t,
|
|
256
|
+
warnings: n
|
|
257
|
+
}) : {
|
|
258
|
+
valid: !1,
|
|
259
|
+
errors: [{
|
|
260
|
+
path: "",
|
|
261
|
+
message: "the document must be an object"
|
|
262
|
+
}],
|
|
263
|
+
warnings: n
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
export { y as validateActionDocument };
|
|
@@ -16,10 +16,15 @@ export declare const onAuthFailure: (listener: AuthFailureListener) => (() => vo
|
|
|
16
16
|
* What an HTTP refusal means for the session. Stated once, because the provider and the network layers must not
|
|
17
17
|
* disagree about which refusals are renewable.
|
|
18
18
|
*
|
|
19
|
-
* A backend that names the reason (Plitzi's API answers `reason` on every 401) is
|
|
20
|
-
* gets the benefit of the doubt — an unexplained 401 is treated as renewable, so a
|
|
21
|
-
* refused renewal instead of signing out a session that was still good.
|
|
22
|
-
*
|
|
19
|
+
* Only a 401 is about the session. A backend that names the reason (Plitzi's API answers `reason` on every 401) is
|
|
20
|
+
* believed; one that says nothing gets the benefit of the doubt — an unexplained 401 is treated as renewable, so a
|
|
21
|
+
* stale access token costs one refused renewal instead of signing out a session that was still good.
|
|
22
|
+
*
|
|
23
|
+
* A 403 is never about the session, whatever it carries. It is "you may not do THIS": a permission the account does
|
|
24
|
+
* not hold, or a CSRF check that failed — and the kernel's CSRF refusal names reasons (`missing`, `expired`) that are
|
|
25
|
+
* spelled like session ones. It used to be read as `inactive`, so any screen that asked for something its visitor may
|
|
26
|
+
* not have signed that visitor out on the spot, with nothing on the page to say why. An account that really was
|
|
27
|
+
* deactivated is refused with a 401 naming `inactive`, which is still believed.
|
|
23
28
|
*/
|
|
24
29
|
export declare const authFailureFromResponse: (status: number, body?: unknown) => AuthFailureReason | undefined;
|
|
25
30
|
/**
|
|
@@ -6,13 +6,14 @@ var e = /* @__PURE__ */ new Set(), t = (t) => {
|
|
|
6
6
|
"expired",
|
|
7
7
|
"revoked",
|
|
8
8
|
"inactive",
|
|
9
|
+
"unverified",
|
|
9
10
|
"malformed",
|
|
10
11
|
"outdated",
|
|
11
12
|
"network"
|
|
12
13
|
], i = (e, t) => {
|
|
13
|
-
if (e
|
|
14
|
+
if (e !== 401) return;
|
|
14
15
|
let n = t?.reason;
|
|
15
|
-
return typeof n == "string" && r.includes(n) ? n :
|
|
16
|
+
return typeof n == "string" && r.includes(n) ? n : "expired";
|
|
16
17
|
}, a = (e) => /([^.]+\.[^.]+)$/.exec(e)?.[1] ?? e, o = (e, t) => {
|
|
17
18
|
if (!e || !t) return !1;
|
|
18
19
|
try {
|