your-ai-workflow-firebase-os 2.0.0 → 2.0.2
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/{ContactPopup-Du_AVUgk.js → ContactPopup-Dsg2ntq3.js} +3606 -3560
- package/dist/ContactPopup-IwBm-eqz.cjs +12 -0
- package/dist/components/ViewingAs.d.ts +9 -2
- package/dist/components/media/Attachments.d.ts +15 -0
- package/dist/lib/pageDesignLines.d.ts +1 -1
- package/dist/lib/payments.d.ts +23 -2
- package/dist/lib/people.d.ts +9 -0
- package/dist/lib/recordsKey.d.ts +24 -0
- package/dist/lib/rowPress.d.ts +36 -0
- package/dist/lib/steps.d.ts +7 -0
- package/dist/lib/transactions.d.ts +13 -1
- package/dist/lib/uploadQueue.d.ts +6 -0
- package/dist/pages/PagesAdmin.d.ts +49 -7
- package/dist/renderer.cjs.js +1 -1
- package/dist/renderer.es.js +1 -1
- package/dist/server.cjs.js +1 -1
- package/dist/server.es.js +1 -1
- package/dist/{validate-C_iJKXDU.js → validate-DzSJWuyL.js} +52 -31
- package/dist/validate-e48WXJdP.cjs +103 -0
- package/dist/vite.cjs.js +1 -1
- package/dist/vite.es.js +1 -1
- package/dist/your-ai-workflow-firebase-os.cjs.js +56 -56
- package/dist/your-ai-workflow-firebase-os.css +1 -1
- package/dist/your-ai-workflow-firebase-os.es.js +8377 -8177
- package/package.json +1 -1
- package/dist/ContactPopup-MalER7E7.cjs +0 -12
- package/dist/validate-L8QWFfBP.cjs +0 -103
|
@@ -57,10 +57,17 @@ export declare function useViewingAs({ on, everyone }: {
|
|
|
57
57
|
everyone?: boolean;
|
|
58
58
|
}): ViewingAs;
|
|
59
59
|
/**
|
|
60
|
-
* The switch with its word
|
|
60
|
+
* The switch with its word BESIDE it, for a toolbar that wants one line.
|
|
61
|
+
*
|
|
62
|
+
* The word is drawn here and not by the select, which stacks its label above
|
|
63
|
+
* the trigger the way a form field does: in a toolbar that made the bar two
|
|
64
|
+
* rows tall, so "Viewing" floated over the row while the eye, the switch and
|
|
65
|
+
* every button beside it centred against the taller box. One line, one
|
|
66
|
+
* baseline — the eye, the word, the switch.
|
|
61
67
|
*
|
|
62
68
|
* The eye is the same glyph the console uses for looking at something without
|
|
63
|
-
* changing it, and
|
|
69
|
+
* changing it, and it stays on a phone while the word goes, the way every
|
|
70
|
+
* other row up here is icons on a phone and words on a screen.
|
|
64
71
|
*/
|
|
65
72
|
export declare function ViewingAsBar({ viewing }: {
|
|
66
73
|
viewing: ViewingAs;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AttachmentsProps {
|
|
2
|
+
/** The answer as it sits on the entry — one link, or several. */
|
|
3
|
+
value: unknown;
|
|
4
|
+
/** The file to show large. The screen keeps the viewer. */
|
|
5
|
+
onOpen: (file: {
|
|
6
|
+
src: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
/** The tile's size, where a screen wants them smaller than the Inbox's. */
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function Attachments({ value, onOpen, className }: AttachmentsProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare namespace Attachments {
|
|
14
|
+
var displayName: string;
|
|
15
|
+
}
|
|
@@ -102,7 +102,7 @@ export declare const PIECES_LINE = "And the hard parts are the app\u2019s own pi
|
|
|
102
102
|
* that keeps many things — and names no piece: rule 6 and rule 31 do, and
|
|
103
103
|
* `whole-records` is the build's half.
|
|
104
104
|
*/
|
|
105
|
-
export declare const WORKING_VIEW_LINE = "If this page keeps many things \u2014 orders, requests, clients \u2014 show them the way a professional tool does, so a dozen can be seen at once without my asking for it: each one a compact card or a single row saying only what tells it apart \u2014 its number or name, who it is for, its stage as a small label, when, how much, who has it \u2014 and pressing one opens the whole of it in the app\u2019s own pop-up, where everything done to it is: its stage, its notes, handing it over. Where things move through stages, the people who work on them see a board of those stages; somebody who only follows their own sees theirs as a short list. Never every one drawn open, one big box under another. Inside the opened one, keep it tidy and even: a clear grid, each label above its value
|
|
105
|
+
export declare const WORKING_VIEW_LINE = "If this page keeps many things \u2014 orders, requests, clients \u2014 show them the way a professional tool does, so a dozen can be seen at once without my asking for it: each one a compact card or a single row saying only what tells it apart \u2014 its number or name, who it is for, its stage as a small label, when, how much, who has it \u2014 and pressing one opens the whole of it in the app\u2019s own pop-up, where everything done to it is: its stage, its notes, handing it over. Where things move through stages, the people who work on them see a board of those stages; somebody who only follows their own sees theirs as a short list. Never every one drawn open, one big box under another. Inside the opened one, keep it tidy and even: the pop-up is its one frame, so its parts are set apart by space or a thin rule and never each in a bordered box of its own, nothing boxed inside a box; a clear grid, each label in small print above its value at the page\u2019s ordinary size, one spacing throughout, boxes and buttons that sit side by side the same height, and what can be done to it \u2014 its stage, who holds it, a note \u2014 together in one place at the end rather than scattered through it; nothing on it pulses, and every word on it is mine or the entry\u2019s, never a made-up place, carrier or name standing in for one that is missing. Do not add a gallery to a page I did not ask it for.";
|
|
106
106
|
export declare const finishLine: (website: boolean) => string;
|
|
107
107
|
/**
|
|
108
108
|
* A change sentence's first rule: what the owner's words are about is the
|
package/dist/lib/payments.d.ts
CHANGED
|
@@ -164,13 +164,34 @@ export declare function openBillingPortal(): Promise<string | null>;
|
|
|
164
164
|
* that URL. Only `paid: true` from here means money moved.
|
|
165
165
|
*/
|
|
166
166
|
export declare function confirmPayment(sessionId: string): Promise<PaymentConfirmation>;
|
|
167
|
-
|
|
167
|
+
export interface PaymentsStatus {
|
|
168
|
+
configured: boolean;
|
|
169
|
+
mode: 'live' | 'test' | null;
|
|
170
|
+
}
|
|
171
|
+
/** How often a watching screen asks again while the key is still not in. */
|
|
172
|
+
export declare const STATUS_WATCH_MS = 5000;
|
|
173
|
+
/**
|
|
174
|
+
* Forget the cached /payments/status answer and ask again — the Payments
|
|
175
|
+
* switch, and tests. Anything on screen holding the old answer is told.
|
|
176
|
+
*/
|
|
168
177
|
export declare function resetPaymentsStatus(): void;
|
|
178
|
+
/**
|
|
179
|
+
* An answer the status route gave SOMEWHERE ELSE — the polled chips on the
|
|
180
|
+
* Setup, Payments and Go live screens (lib/serviceStatus.ts). The screen that
|
|
181
|
+
* tells the owner their key is in is the screen that tells the app, so walking
|
|
182
|
+
* from there to the Pages screen finds the Payments section already there.
|
|
183
|
+
*/
|
|
184
|
+
export declare function notePaymentsStatus(data: any): void;
|
|
169
185
|
/**
|
|
170
186
|
* Whether the owner has connected Stripe. A page uses this to avoid drawing a
|
|
171
187
|
* Pay button that cannot work on an app whose owner is still mid-setup.
|
|
188
|
+
*
|
|
189
|
+
* `watch` is for the screens an owner sets payments up FROM — they ask again
|
|
190
|
+
* every few seconds until the key is in, so a section appears where the owner
|
|
191
|
+
* is standing rather than after a reload. It stops itself the moment the
|
|
192
|
+
* answer turns true, so an app that is set up polls nothing.
|
|
172
193
|
*/
|
|
173
|
-
export declare function usePaymentsEnabled(): {
|
|
194
|
+
export declare function usePaymentsEnabled(watch?: boolean): {
|
|
174
195
|
loading: boolean;
|
|
175
196
|
configured: boolean;
|
|
176
197
|
mode: 'live' | 'test' | null;
|
package/dist/lib/people.d.ts
CHANGED
|
@@ -6,6 +6,15 @@ export interface Person {
|
|
|
6
6
|
name: string;
|
|
7
7
|
/** Their picture, or '' — most installs keep none on the profile. */
|
|
8
8
|
photo: string;
|
|
9
|
+
/**
|
|
10
|
+
* Their address, or '' — beside the name in a picker, so two people who
|
|
11
|
+
* share a name are told apart and a name that IS an address is not the
|
|
12
|
+
* only thing known about them. Only the team and admins ever list people,
|
|
13
|
+
* so it reaches nobody a profile does not already reach.
|
|
14
|
+
*/
|
|
15
|
+
email: string;
|
|
16
|
+
/** The number they signed in with, or ''. */
|
|
17
|
+
phone: string;
|
|
9
18
|
/** The word they are marked with, which is the word that was asked for. */
|
|
10
19
|
role: string;
|
|
11
20
|
}
|
package/dist/lib/recordsKey.d.ts
CHANGED
|
@@ -28,3 +28,27 @@ export declare function pageRecordsCollection(config: any, prefix: string, id?:
|
|
|
28
28
|
* no preset draws no record list of its own).
|
|
29
29
|
*/
|
|
30
30
|
export declare function recordsKeyInUse(config: any, id: string, isPublic: boolean): string;
|
|
31
|
+
/**
|
|
32
|
+
* The word a page of SENT entries names its collection after: its tab name
|
|
33
|
+
* as the sentence has always folded it — lower case, one `_` between words,
|
|
34
|
+
* none at either end — behind the key the page keeps once it has been
|
|
35
|
+
* renamed or moved, so a rename never sends the road to an empty list.
|
|
36
|
+
*/
|
|
37
|
+
export declare const casePageName: (config: any) => string;
|
|
38
|
+
/**
|
|
39
|
+
* The ONE collection a page whose entries are sent keeps them in —
|
|
40
|
+
* `case_orders_entries` for a page called Orders.
|
|
41
|
+
*
|
|
42
|
+
* Three things have to agree on it to the letter, and until 2026-09-24 only
|
|
43
|
+
* two did. The page's sentence hands the assistant this name
|
|
44
|
+
* (`useCases('case_orders_entries')`), and the arrival road writes a shop's
|
|
45
|
+
* orders into it (lib/arrivalRoads.ts). But the page templates handed the
|
|
46
|
+
* content file its `actions` — `records`, `saveRecord`, `updateRecord`,
|
|
47
|
+
* `deleteRecord`, `collection` — bound to `case_<name>_records`, the shape
|
|
48
|
+
* every other page has, and nothing else ever read or wrote that name. So
|
|
49
|
+
* `actions.updateRecord(order.id, …)` on an order that had arrived answered
|
|
50
|
+
* "No document to update: …/case_orders_records/<id>": the order sat one
|
|
51
|
+
* collection over under the same id, and the first anybody heard of it was
|
|
52
|
+
* the owner pressing Assign. Named here, once, and read by all three.
|
|
53
|
+
*/
|
|
54
|
+
export declare const caseEntriesCollection: (config: any, prefix?: string) => string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Was that click a PRESS on the row, or the tail of a text selection?
|
|
3
|
+
*
|
|
4
|
+
* The admin lists — Pages, Forms — are cards that open when you click them
|
|
5
|
+
* and shut when you click them again, and the handler sits on the whole
|
|
6
|
+
* card, so the open settings are inside the very element that folds them.
|
|
7
|
+
* Everything drawn in there stops the click from reaching it, which works
|
|
8
|
+
* for an ordinary click and not at all for a SELECTION: dragging across a
|
|
9
|
+
* hint, a sentence or a label starts on one element and ends on another, so
|
|
10
|
+
* the browser fires the click on the nearest thing that holds them both —
|
|
11
|
+
* the card — above every guard inside it. The owner's words, 2026-09-24:
|
|
12
|
+
* "if you select text inside a page settings anywhere it folds page
|
|
13
|
+
* settings which is super annoying".
|
|
14
|
+
*
|
|
15
|
+
* So the card asks this instead. A press is a press: down and up in the same
|
|
16
|
+
* spot, with no text left selected. A drag is not, wherever it landed, and
|
|
17
|
+
* neither is a click that ends with words highlighted — a double-click on a
|
|
18
|
+
* word, a triple-click on a line, a drag across a paragraph.
|
|
19
|
+
*
|
|
20
|
+
* Clicking to CLOSE a row still works after a selection: the mouse going
|
|
21
|
+
* down clears it, so by the time the click lands there is nothing selected.
|
|
22
|
+
*/
|
|
23
|
+
/** How far the mouse may travel between down and up and still be a press. */
|
|
24
|
+
export declare const PRESS_SLOP = 4;
|
|
25
|
+
export interface PressPoint {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `from` is where the mouse went down on the card, or null when the click
|
|
31
|
+
* came from somewhere that never pressed it — a keyboard, or a test.
|
|
32
|
+
*/
|
|
33
|
+
export declare const isRowPress: (at: {
|
|
34
|
+
clientX: number;
|
|
35
|
+
clientY: number;
|
|
36
|
+
}, from: PressPoint | null) => boolean;
|
package/dist/lib/steps.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ export interface StepsState<T extends string = string> {
|
|
|
16
16
|
goTo: (id: T) => void;
|
|
17
17
|
/** Back to the first step with the question taken off the address — for when the thing is sent. */
|
|
18
18
|
reset: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* A file somewhere in the app is still going up, so the step is held: every
|
|
21
|
+
* way off it does nothing but say so. For a page that wants its own button
|
|
22
|
+
* to show it — `<Button disabled={flow.waiting}>` — rather than let somebody
|
|
23
|
+
* press a button that will not move.
|
|
24
|
+
*/
|
|
25
|
+
waiting: boolean;
|
|
19
26
|
/** Everything `<StepBar>` needs: `<StepBar {...flow.bar} />`. */
|
|
20
27
|
bar: {
|
|
21
28
|
steps: StepInfo<T>[];
|
|
@@ -118,6 +118,12 @@ export declare function splitCollected(collected: [string, unknown][]): {
|
|
|
118
118
|
};
|
|
119
119
|
/** A metadata value is always a string; one that holds JSON is read as what it holds. */
|
|
120
120
|
export declare function readValue(value: unknown): unknown;
|
|
121
|
+
/**
|
|
122
|
+
* A key that holds a PICTURE rather than something to read. Anywhere an
|
|
123
|
+
* entry's own keys are printed — a receipt line, a sent list in the Inbox —
|
|
124
|
+
* this one is either drawn or left out, never said as an address.
|
|
125
|
+
*/
|
|
126
|
+
export declare const isPictureKey: (key: string) => boolean;
|
|
121
127
|
/**
|
|
122
128
|
* One thing bought, as a line: "2 × Blazer — Noir Black, M · £240". The
|
|
123
129
|
* page named the keys itself, so each part is found by the names pages
|
|
@@ -125,10 +131,14 @@ export declare function readValue(value: unknown): unknown;
|
|
|
125
131
|
* follows as "label: value".
|
|
126
132
|
*/
|
|
127
133
|
export declare function itemLine(item: Record<string, unknown>, currency?: string | null): string;
|
|
128
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* The same thing with its price apart — the words for the left of a receipt
|
|
136
|
+
* line, the sum for the right, and the picture for the line to draw.
|
|
137
|
+
*/
|
|
129
138
|
export declare function itemParts(item: Record<string, unknown>, currency?: string | null): {
|
|
130
139
|
words: string;
|
|
131
140
|
price: string;
|
|
141
|
+
picture: string;
|
|
132
142
|
};
|
|
133
143
|
/**
|
|
134
144
|
* A collected value as the lines it reads as. A list of things bought is
|
|
@@ -142,6 +152,8 @@ export interface ReceiptLine {
|
|
|
142
152
|
right: string;
|
|
143
153
|
/** A thing bought; a number that made up the amount or a choice (delivery, a discount, the plan, the seats); the total. */
|
|
144
154
|
kind: 'item' | 'extra' | 'total';
|
|
155
|
+
/** The thing's own picture, where the page put one on the line — drawn beside its words, never printed as an address. */
|
|
156
|
+
picture?: string;
|
|
145
157
|
}
|
|
146
158
|
/**
|
|
147
159
|
* What was bought, as the lines of a receipt: each thing on a line of its
|
|
@@ -102,6 +102,12 @@ export declare class UploadQueue<T = unknown> {
|
|
|
102
102
|
private pump;
|
|
103
103
|
private run;
|
|
104
104
|
}
|
|
105
|
+
/** How many files are going up that walking away from would stop. */
|
|
106
|
+
export declare const uploadsStoppedByLeaving: () => number;
|
|
107
|
+
/** Hear when that number changes. Hands back the way to stop hearing. */
|
|
108
|
+
export declare function watchUploads(heard: () => void): () => void;
|
|
109
|
+
/** The same number, for a component — it redraws as each file lands. */
|
|
110
|
+
export declare const useUploadsStoppedByLeaving: () => number;
|
|
105
111
|
/** The list in numbers — what a button or a status line says. */
|
|
106
112
|
export declare function uploadSummary(items: UploadItem[]): {
|
|
107
113
|
total: number;
|
|
@@ -72,13 +72,6 @@ export declare const audienceRoleOptions: (roles?: CustomRole[]) => {
|
|
|
72
72
|
value: string;
|
|
73
73
|
label: string;
|
|
74
74
|
}[];
|
|
75
|
-
/**
|
|
76
|
-
* The collection a page of sent entries keeps them in — the name its sentence
|
|
77
|
-
* hands the assistant (`useCases('case_orders_entries')`), and so the name the
|
|
78
|
-
* app lets a linked page's entries into (arrivalRoads). ONE place, because the
|
|
79
|
-
* two have to agree to the letter.
|
|
80
|
-
*/
|
|
81
|
-
export declare const caseEntriesCollection: (config: any, prefix?: string) => string;
|
|
82
75
|
export declare const audienceLines: (config: any) => string[];
|
|
83
76
|
/** Which groups a piece of the owner's words names, each counted once. */
|
|
84
77
|
export declare const groupsNamed: (text: string, roles?: CustomRole[]) => string[];
|
|
@@ -584,6 +577,7 @@ export declare const pageAddress: (page: {
|
|
|
584
577
|
/** What the owner still has to fill in before the sentence is worth pasting. */
|
|
585
578
|
export declare const promptBlocker: (page: {
|
|
586
579
|
path: string;
|
|
580
|
+
id?: string;
|
|
587
581
|
}, config: any, linkTargets?: WiringPageRow[]) => string;
|
|
588
582
|
/**
|
|
589
583
|
* One thing the owner has handed over for the page — a picture, a video, a
|
|
@@ -1496,6 +1490,54 @@ export declare const arrivalsTo: (config: any) => ArrivalsTo | "";
|
|
|
1496
1490
|
* that is not the receiving end of a road.
|
|
1497
1491
|
*/
|
|
1498
1492
|
export declare const arrivalSources: (config: any, targets: WiringPageRow[]) => WiringPageRow[];
|
|
1493
|
+
/**
|
|
1494
|
+
* The pages anybody can open that are linked to THIS page and make entries,
|
|
1495
|
+
* when this page is one person's own records (`user_`) — where nothing can
|
|
1496
|
+
* ever land.
|
|
1497
|
+
*
|
|
1498
|
+
* The app carries what a visitor makes onto a page whose entries are SENT
|
|
1499
|
+
* (`case_`, arrivalRoads) and onto no other kind: a `user_` record is read by
|
|
1500
|
+
* the one uid on it, so an order could carry the buyer OR the person it is
|
|
1501
|
+
* handed to, never both, and a guest's order nobody at all. There is no road
|
|
1502
|
+
* into `user_`, and there cannot be one.
|
|
1503
|
+
*
|
|
1504
|
+
* The owner's Orders rehearsal of 2026-09-24 was this. Members had to see
|
|
1505
|
+
* their own orders, so she answered "Only the person who added it" — the
|
|
1506
|
+
* reading of an order that anybody would make — and the sentence told the
|
|
1507
|
+
* assistant the shop and the page had "nothing to share". Every assistant
|
|
1508
|
+
* given it built the same page: actions.records on a collection nothing ever
|
|
1509
|
+
* writes, empty for the buyer, the team and the admins, and not a fault
|
|
1510
|
+
* anywhere, because nothing was refused. Regenerated with the context
|
|
1511
|
+
* cleared it came back the same, which is how she knew it was not Gemini.
|
|
1512
|
+
*
|
|
1513
|
+
* So the row says it where she is standing, and the sentence waits: a page
|
|
1514
|
+
* that can never work is not one to hand over. Looked for from both ends,
|
|
1515
|
+
* like arrivalSources, because a link is kept on one of its two rows.
|
|
1516
|
+
*/
|
|
1517
|
+
export declare const deadRoadSources: (config: any, targets: WiringPageRow[]) => WiringPageRow[];
|
|
1518
|
+
/**
|
|
1519
|
+
* The same road seen from the page that MAKES the entries: the pages of one
|
|
1520
|
+
* person's own records this page links to, when this page is one anybody can
|
|
1521
|
+
* open and makes something. Empty for a page that makes nothing.
|
|
1522
|
+
*/
|
|
1523
|
+
export declare const deadRoadEnds: (config: any, targets: WiringPageRow[]) => WiringPageRow[];
|
|
1524
|
+
/**
|
|
1525
|
+
* The line under "Who sees what somebody adds here?" on a page nothing can
|
|
1526
|
+
* land on — in place of the answer's own hint, because the answer is wrong
|
|
1527
|
+
* for this page and saying what it does would only confirm it.
|
|
1528
|
+
*/
|
|
1529
|
+
export declare const deadRoadHint: (config: any, targets: WiringPageRow[]) => string;
|
|
1530
|
+
/**
|
|
1531
|
+
* The same, under the link on the row that MAKES the entries — the other
|
|
1532
|
+
* page's setting is not on this row, so the line says where it is.
|
|
1533
|
+
*/
|
|
1534
|
+
export declare const deadRoadEndWords: (target: WiringPageRow) => string;
|
|
1535
|
+
/**
|
|
1536
|
+
* What holds a sentence back on either end of a road with nowhere to end.
|
|
1537
|
+
* A page that can never show what it is for is not one to hand over: the
|
|
1538
|
+
* assistant would build it faithfully, empty, and nothing would say why.
|
|
1539
|
+
*/
|
|
1540
|
+
export declare const roadBlocker: (config: any, targets: WiringPageRow[]) => string;
|
|
1499
1541
|
/**
|
|
1500
1542
|
* What "only the person it is handed to" asks of the page that draws the
|
|
1501
1543
|
* entries. The app keeps a new one from the team by itself; without a way to
|
package/dist/renderer.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-CiTBaPhY.cjs`);const e=require(`./ContactPopup-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-CiTBaPhY.cjs`);const e=require(`./ContactPopup-IwBm-eqz.cjs`);exports.ContactPopup=e.t;
|
package/dist/renderer.es.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "./ContactPopup-
|
|
1
|
+
import { t as e } from "./ContactPopup-Dsg2ntq3.js";
|
|
2
2
|
export { e as ContactPopup };
|
package/dist/server.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./verifiedAccount-D3OeaOBo.cjs`),n=require(`./aiModels-BIhoTNH0.cjs`),r=require(`./validate-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./verifiedAccount-D3OeaOBo.cjs`),n=require(`./aiModels-BIhoTNH0.cjs`),r=require(`./validate-e48WXJdP.cjs`);let i=require(`node:fs`);i=e.a(i,1);let a=require(`express`);a=e.a(a,1);let o=require(`node:crypto`),s=require(`stripe`);s=e.a(s,1);var c=`https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com`,l=60;function u(e,t,n,r=Math.floor(Date.now()/1e3)){return n?e.alg===`RS256`?e.kid?t.aud===n?t.iss===`https://securetoken.google.com/${n}`?t.sub?t.sub.length>128?`Token subject is not a valid uid.`:typeof t.exp!=`number`||t.exp<=r?`Token has expired.`:typeof t.iat!=`number`||t.iat>r+l?`Token was issued in the future.`:null:`Token has no subject.`:`Token has the wrong issuer.`:`Token was issued for a different Firebase project.`:`Token has no key id.`:`Token is not signed with RS256.`:`The server does not know its Firebase project id.`}function d(e){return Buffer.from(e.replace(/-/g,`+`).replace(/_/g,`/`),`base64`)}function f(e){let t=String(e||``).split(`.`);if(t.length!==3)return null;try{return{header:JSON.parse(d(t[0]).toString(`utf8`)),claims:JSON.parse(d(t[1]).toString(`utf8`)),signed:`${t[0]}.${t[1]}`,signature:d(t[2])}}catch{return null}}var p=null;async function m(){if(p&&p.expiresAt>Date.now())return p.keys;let e=await fetch(c);if(!e.ok)throw Error(`Could not fetch Google signing keys (${e.status}).`);let t=await e.json(),n=/max-age=(\d+)/.exec(e.headers.get(`cache-control`)||``);return p={keys:t,expiresAt:Date.now()+(n?Number(n[1]):3600)*1e3},t}async function h(e,t){let n=f(e);if(!n)throw Error(`That is not a valid sign-in token.`);let r=u(n.header,n.claims,t);if(r)throw Error(r);let i=(await m())[n.header.kid];if(!i)throw Error(`Token was signed with a key Google no longer publishes.`);let a=(0,o.createVerify)(`RSA-SHA256`);if(a.update(n.signed),a.end(),!a.verify(i,n.signature))throw Error(`Token signature does not check out.`);return{uid:n.claims.sub,email:n.claims.email||null,emailVerified:!!n.claims.email_verified,signInProvider:n.claims.firebase?.sign_in_provider||null}}function g(){return(process.env.VITE_FIREBASE_PROJECT_ID||process.env.FIREBASE_PROJECT_ID||``).trim()}var _=`https://firestore.googleapis.com/v1`;function v(e){return e==null?null:`stringValue`in e?e.stringValue:`integerValue`in e?Number(e.integerValue):`doubleValue`in e?e.doubleValue:`booleanValue`in e?e.booleanValue:`timestampValue`in e?e.timestampValue:`nullValue`in e?null:`mapValue`in e?y(e.mapValue?.fields||{}):`arrayValue`in e?(e.arrayValue?.values||[]).map(v):null}function y(e){let t={};for(let[n,r]of Object.entries(e||{}))t[n]=v(r);return t}function ee(e,t){let n=`${e}/${t}`.split(`/`);if(n.length%2!=0)return`That is not a document path.`;for(let e of n)if(!e||e===`.`||e===`..`||!/^[A-Za-z0-9_.@~+-]+$/.test(e))return`That is not a document path.`;return null}async function b(e,t,n,r){let i=ee(t,n);if(i)throw Error(i);let a=`${_}/projects/${e}/databases/(default)/documents/${t}/${n}`,o=await fetch(a,{headers:r?{Authorization:`Bearer ${r}`}:{}});if(o.status===404)return null;if(o.status===403)throw Error(`You do not have permission to read that record.`);if(!o.ok)throw Error(`Firestore refused the read (${o.status}).`);return y((await o.json()).fields||{})}async function te(e,t,n){if(!/^[A-Za-z0-9_.@~+-]+$/.test(t)||t===`.`||t===`..`)throw Error(`That is not a collection.`);let r=`${_}/projects/${e}/databases/(default)/documents/${t}?pageSize=300`,i=await fetch(r,{headers:n?{Authorization:`Bearer ${n}`}:{}});if(i.status===403)throw Error(`You do not have permission to read those records.`);if(!i.ok)throw Error(`Firestore refused the read (${i.status}).`);return((await i.json()).documents||[]).map(e=>({id:String(e.name||``).split(`/`).pop()||``,data:y(e.fields||{})}))}var ne=[`email`,`Email`,`emailAddress`,`email_address`,`userEmail`,`contactEmail`,`submitterEmail`];function re(e){for(let t of ne){let n=e[t];if(typeof n==`string`&&n.includes(`@`))return n.trim()}return null}var ie=4320*60*1e3,ae=new Set([`user`,`users`,`free`,`guest`,`guests`,`internal`,`admin`,`admins`,`public`,`owner`,`team`,`member`,`members`,`none`,`role`,`roles`]),oe=e=>typeof e==`string`&&/^[a-z][a-z0-9]{1,23}$/.test(e)&&!ae.has(e),se=e=>(0,o.createHmac)(`sha256`,e).update(`your-ai-firebase plan roles v1`).digest(`hex`),ce=(e,t,n,r)=>(0,o.createHash)(`sha256`).update(`${e}:${t}:${n}:${r}`).digest(`hex`);function le(e){let t=new Map;for(let n of e){let e=Array.isArray(n?.plans)?n.plans:[];for(let n of e){let e=String(n?.roleId||``);if(oe(e))for(let r of[n?.monthly,n?.yearly])for(let n of[r?.priceId,r?.livePriceId]){let r=String(n||``).trim();r&&t.set(r,e)}}}return t}var ue=e=>le(e).size>0;function de(e,t,n){let r=null;for(let i of e){if(!i.active||!i.priceId)continue;let e=t.get(i.priceId);if(!e)continue;let a=typeof i.currentPeriodEnd==`number`?i.currentPeriodEnd*1e3:n,o=Math.round(Math.max(a,n)+ie);(!r||o>r.until)&&(r={role:e,until:o})}return r}var fe=`https://api.resend.com/emails`;function pe(){return(process.env.RESEND_API_KEY||``).trim()}function x(){return(process.env.EMAIL_FROM||``).trim()||`onboarding@resend.dev`}function me(){return(process.env.EMAIL_REPLY_TO||``).trim()||void 0}function S(){return(process.env.VITE_ADMIN_EMAILS||process.env.ADMIN_EMAILS||``).split(/[,\s]+/).map(e=>e.trim().toLowerCase()).filter(e=>e.includes(`@`))}var he={appName:``,logoUrl:``,appUrl:``,accent:`#7c3aed`,foreground:`#1e1b4b`,buttonText:``,buttonGradient:[],panelBg:``,panelBorder:``};function C(e,t){let n=String(e??``).trim();return/^#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(n)?n:t}function ge(e){let t=String(e??``).trim();return t.length>2e3||/[\s"'<>]/.test(t)?``:/^https?:\/\/[^/]+/i.test(t)?t:``}function _e(e){return String(e??``).replace(/[\r\n\t<>]/g,` `).replace(/\s+/g,` `).trim().slice(0,60)}function ve(e){let t=e&&typeof e==`object`?e:{},n=Array.isArray(t.buttonGradient)?t.buttonGradient.map(e=>C(e,``)).filter(Boolean).slice(0,2):[];return{appName:_e(t.appName),logoUrl:ge(t.logoUrl),appUrl:ge(t.appUrl),accent:C(t.accent,he.accent),foreground:C(t.foreground,he.foreground),buttonText:C(t.buttonText,``),buttonGradient:n,panelBg:C(t.panelBg,``),panelBorder:C(t.panelBorder,``)}}function ye(e){let t=e.replace(`#`,``);if(t.length===3&&(t=t.split(``).map(e=>e+e).join(``)),t.length<6)return null;let n=parseInt(t.slice(0,6),16);return Number.isNaN(n)?null:[n>>16&255,n>>8&255,n&255]}function be(e,t,n=[255,255,255]){let r=ye(e);return r?`#`+r.map((e,r)=>Math.round(e+(n[r]-e)*t)).map(e=>e.toString(16).padStart(2,`0`)).join(``):e}function xe(e){let t=ye(e);return t?(.299*t[0]+.587*t[1]+.114*t[2])/255:1}function Se(e,t=`#1f2937`,n=`#ffffff`){return xe(e)>.6?t:n}function Ce(e){let t=e.accent,n=xe(e.foreground)>.55?he.foreground:e.foreground,r=e.buttonGradient[0]||be(t,.22,[0,0,0]),i=e.buttonGradient[1]||(e.buttonGradient[0]?e.buttonGradient[0]:t),a=e.panelBg||be(t,.94);return{accent:t,text:n,muted:`#6b7280`,faint:`#9ca3af`,g0:r,g1:i,btnFg:e.buttonText||Se(r),panelBg:a,panelBorder:e.panelBorder||(e.panelBg?be(e.panelBg,.12,[0,0,0]):be(t,.84)),hr:be(t,.88)}}var w={test:{audience:`admins`,look:`notification`,kicker:`Test`,subject:`Test email from {{appName}}`,title:`{{appName}} can send email`,opener:`{{appName}} can send email`,body:`This is a test. If you are reading it, the connection works and every email your app sends will look like this one.
|
|
2
2
|
|
|
3
3
|
Sent {{now}}.`,button:{label:`Open the app`},description:`Proves the connection works. Goes to the admin addresses.`},new_submission:{audience:`admins`,look:`notification`,kicker:`New form entry`,subject:`New {{formName}} submission`,title:`Someone filled in {{formName}}`,opener:`Someone filled in {{formName}}`,body:`{{summary}}`,facts:[[`Name`,`{{name}}`],[`Email`,`{{email}}`]],button:{label:`Open the inbox`,path:`/inbox`},description:`Lets you know someone filled in a form.`},submission_received:{audience:`record`,look:`text`,kicker:`Received`,subject:`We got your message`,title:`We got your message`,greeting:`Hi {{name}},`,body:`Thanks for getting in touch — we have your message and will come back to you shortly.
|
|
4
4
|
|
package/dist/server.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as e, c as t, h as n, t as r, u as i, w as a } from "./verifiedAccount-C1iCxopN.js";
|
|
2
2
|
import { a as o, c as s, i as c, l, m as u, n as d, o as f, r as p, s as m, t as h, u as g } from "./aiModels-BHlEfuRJ.js";
|
|
3
|
-
import { _, a as v, i as ee, p as te } from "./validate-
|
|
3
|
+
import { _, a as v, i as ee, p as te } from "./validate-DzSJWuyL.js";
|
|
4
4
|
import * as ne from "node:fs";
|
|
5
5
|
import y from "express";
|
|
6
6
|
import { createHash as re, createHmac as ie, createVerify as ae } from "node:crypto";
|
|
@@ -308,13 +308,13 @@ var D = (e) => E(y(e)), O = /\b(?:useAiChat|askAi|useAiEnabled|useAiModels)\b|ge
|
|
|
308
308
|
"raw-html": "breaks",
|
|
309
309
|
"own-money": "breaks",
|
|
310
310
|
"dead-click": "breaks",
|
|
311
|
-
"glyph-icon": "
|
|
312
|
-
"own-spinner": "
|
|
313
|
-
"tiny-text": "
|
|
311
|
+
"glyph-icon": "looks",
|
|
312
|
+
"own-spinner": "looks",
|
|
313
|
+
"tiny-text": "looks",
|
|
314
314
|
"vague-button": "breaks",
|
|
315
315
|
"extra-press": "breaks",
|
|
316
|
-
"icon-in-heading": "
|
|
317
|
-
"decorated-empty": "
|
|
316
|
+
"icon-in-heading": "looks",
|
|
317
|
+
"decorated-empty": "looks",
|
|
318
318
|
"item-key": "breaks",
|
|
319
319
|
"whole-records": "breaks"
|
|
320
320
|
};
|
|
@@ -1014,7 +1014,7 @@ function _r(e) {
|
|
|
1014
1014
|
if (J ? c("own-basket", zr.test(i) ? Vr(t, J, /<Checkout\b/.test(i)) : Hr(t, J)) : Y ? c("own-checkout", Lr(t, Y)) : Ur(i) && c("own-purchase", Wr(t)), !J && !Y) for (let n of Wa(i, e)) n.why === "flag" ? c("order-flag", io(n.config, t)) : n.why === "asks" ? c("order-asks", Ga(n.config, t)) : c("buyer-form", ao(n.config, t));
|
|
1015
1015
|
let Ae = Kr(i);
|
|
1016
1016
|
Ae && c("own-return", qr(t, Ae));
|
|
1017
|
-
for (let n of Ja(i, e)) n.why === "typed" ? c("no-road-in", no(n.target, t, n.formId)) : c("own-road", ro(n, t));
|
|
1017
|
+
for (let n of Ja(t, i, e)) n.why === "typed" ? c("no-road-in", no(n.target, t, n.formId)) : c("own-road", ro(n, t));
|
|
1018
1018
|
let Fe = Qi(i);
|
|
1019
1019
|
Fe.length && c("swallowed-write", aa(t, Fe));
|
|
1020
1020
|
let Ie = ra(i);
|
|
@@ -1440,38 +1440,59 @@ var wa = (e, t) => `${e}: ${P(t)} — the page works out WHO MADE a record for i
|
|
|
1440
1440
|
}));
|
|
1441
1441
|
}
|
|
1442
1442
|
return r;
|
|
1443
|
-
}, Ga = (e, t) => `${e}: this is the order ${t} sends back beside its <PayButton>, and an order asks the buyer NOTHING (fields: []) — who is paying is their ACCOUNT. Put <BuyerDetails onReady={setBuyer} phone address /> from 'your-ai-workflow-firebase-os' before the form, take every name, email, phone and address question out of the form, spread { ...buyer.metadata } into the button's metadata, and carry buyer.name, buyer.email, buyer.phone and buyer.address in the form's extra with the items. Asked through the form, the buyer has no account: their order can never be shown back to them, and a page built on these entries — an Orders page each buyer sees their own on — has nobody to send it to (contract rule 9).`, Ka = /(?:\bto|\bhref|\borderPath)=\{?\s*['"`]\/([A-Za-z0-9_-]+)[?'"`]|\bnavigate\(\s*['"`]\/([A-Za-z0-9_-]+)[?'"`]/g, $ = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, ""), qa = /\baddDoc\s*\(\s*collection\s*\(\s*db\s*,\s*['"`]case_|\bsetDoc\s*\(\s*doc\s*\(\s*collection\s*\(\s*db\s*,\s*['"`]case_/, Ja = (e, t) => {
|
|
1444
|
-
let
|
|
1445
|
-
let n =
|
|
1446
|
-
return
|
|
1447
|
-
}),
|
|
1448
|
-
if (!
|
|
1449
|
-
let
|
|
1450
|
-
for (let
|
|
1451
|
-
let
|
|
1452
|
-
if (!
|
|
1453
|
-
|
|
1454
|
-
let
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1443
|
+
}, Ga = (e, t) => `${e}: this is the order ${t} sends back beside its <PayButton>, and an order asks the buyer NOTHING (fields: []) — who is paying is their ACCOUNT. Put <BuyerDetails onReady={setBuyer} phone address /> from 'your-ai-workflow-firebase-os' before the form, take every name, email, phone and address question out of the form, spread { ...buyer.metadata } into the button's metadata, and carry buyer.name, buyer.email, buyer.phone and buyer.address in the form's extra with the items. Asked through the form, the buyer has no account: their order can never be shown back to them, and a page built on these entries — an Orders page each buyer sees their own on — has nobody to send it to (contract rule 9).`, Ka = /(?:\bto|\bhref|\borderPath)=\{?\s*['"`]\/([A-Za-z0-9_-]+)[?'"`]|\bnavigate\(\s*['"`]\/([A-Za-z0-9_-]+)[?'"`]/g, $ = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, ""), qa = /\baddDoc\s*\(\s*collection\s*\(\s*db\s*,\s*['"`]case_|\bsetDoc\s*\(\s*doc\s*\(\s*collection\s*\(\s*db\s*,\s*['"`]case_/, Ja = (e, t, n) => {
|
|
1444
|
+
let r = (e) => [...t.matchAll(RegExp(`<${e}\\b`, "g"))].map((e) => {
|
|
1445
|
+
let n = e.index ?? 0, r = t.indexOf("/>", n);
|
|
1446
|
+
return t.slice(n, r === -1 ? n + 800 : r + 2);
|
|
1447
|
+
}), i = [...r("Basket"), ...r("Checkout")].find((e) => /\bformId=/.test(e)), a = (i ?? r("ContactPopup").find((e) => /\bextra=/.test(e)))?.match(/formId=\{?\s*['"`]([^'"`]+)['"`]/)?.[1];
|
|
1448
|
+
if (!a) return [];
|
|
1449
|
+
let o = [], s = /* @__PURE__ */ new Set(), c = [];
|
|
1450
|
+
for (let e of t.matchAll(Ka)) {
|
|
1451
|
+
let t = $(e[1] || e[2] || "");
|
|
1452
|
+
if (!t || s.has(t)) continue;
|
|
1453
|
+
s.add(t);
|
|
1454
|
+
let r = n.find((e) => R(e.file) && $(I(e.file).replace(/Content\.tsx$/, "")) === t);
|
|
1455
|
+
r && c.push(r);
|
|
1456
|
+
}
|
|
1457
|
+
let l = (e) => {
|
|
1458
|
+
let t = z(e.source), n = t.match(/\buseCases(?:<[^>]*>)?\s*\(\s*['"`](case_[A-Za-z0-9_]+)['"`]/)?.[1] ?? `case_${I(e.file).replace(/Content\.tsx$/, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase()}_entries`;
|
|
1459
|
+
return {
|
|
1460
|
+
theirs: t,
|
|
1461
|
+
gap: {
|
|
1462
|
+
target: e.file,
|
|
1463
|
+
formId: a,
|
|
1464
|
+
paid: !!i,
|
|
1465
|
+
reads: n
|
|
1466
|
+
}
|
|
1461
1467
|
};
|
|
1462
|
-
|
|
1463
|
-
|
|
1468
|
+
}, u = (e) => {
|
|
1469
|
+
let t = e.match(da)?.[1], n = RegExp(`['"\`]${a.replace(/[^A-Za-z0-9_-]/g, "")}['"\`]`).test(e);
|
|
1470
|
+
return t && n && !/\bappliedEntries\b/.test(e) ? t : void 0;
|
|
1471
|
+
};
|
|
1472
|
+
for (let e of c) {
|
|
1473
|
+
let { theirs: t, gap: n } = l(e);
|
|
1474
|
+
!/\b(?:usePublished|publish)\s*\(/.test(t) && /\buseCases\s*\(/.test(t) && qa.test(t) && o.push({
|
|
1475
|
+
...n,
|
|
1464
1476
|
why: "typed",
|
|
1465
1477
|
inbox: ""
|
|
1466
1478
|
});
|
|
1467
|
-
let
|
|
1468
|
-
|
|
1469
|
-
...
|
|
1479
|
+
let r = u(t);
|
|
1480
|
+
r && o.push({
|
|
1481
|
+
...n,
|
|
1482
|
+
why: "fetched",
|
|
1483
|
+
inbox: r
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
for (let t of n) {
|
|
1487
|
+
if (t.file === e || !R(t.file) || c.includes(t)) continue;
|
|
1488
|
+
let { theirs: n, gap: r } = l(t), i = u(n);
|
|
1489
|
+
i && o.push({
|
|
1490
|
+
...r,
|
|
1470
1491
|
why: "fetched",
|
|
1471
|
-
inbox:
|
|
1492
|
+
inbox: i
|
|
1472
1493
|
});
|
|
1473
1494
|
}
|
|
1474
|
-
return
|
|
1495
|
+
return o;
|
|
1475
1496
|
}, Ya = (e) => {
|
|
1476
1497
|
let t = [], n = /* @__PURE__ */ new Set(), r = (e, r, i) => {
|
|
1477
1498
|
let a = `${$(e)}|${r}`;
|