@stardeck-customer-apps/controls 0.1.0 → 0.3.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/SKILL.md +61 -2
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +16 -0
- package/dist/server/index.cjs +16 -0
- package/dist/server/index.d.cts +18 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.js +16 -0
- package/package.json +2 -2
package/SKILL.md
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
**Package**: `@stardeck-customer-apps/controls`
|
|
4
4
|
|
|
5
5
|
Controls are values Stardeck owns and your app reads while it runs: feature
|
|
6
|
-
flags, what the plan allows,
|
|
7
|
-
|
|
6
|
+
flags, what the plan allows, how many locations have POS Pro hardware, which
|
|
7
|
+
Accounting edition the business pays for, and which payment provider and methods
|
|
8
|
+
the app uses. Your app asks Stardeck about once a minute and keeps the answer in memory.
|
|
8
9
|
A change on Stardeck reaches the app within about a minute, with no deploy.
|
|
9
10
|
|
|
10
11
|
Never invent controls or flags of your own. The list is fixed by Stardeck and
|
|
@@ -48,15 +49,73 @@ the last values stay.
|
|
|
48
49
|
| `flag.paymentsSetupStep` | `boolean` | no |
|
|
49
50
|
| `plan.locations` | `{ included: number \| null, max: number \| null, extraMonthly: { amount, currency } \| null }` | no |
|
|
50
51
|
| `plan.multiEntity` | `boolean` | no |
|
|
52
|
+
| `pos.pro` | `{ locations: number \| null }` | no |
|
|
53
|
+
| `plan.accountingEdition` | `"small" \| "medium" \| null` | no |
|
|
51
54
|
| `payments.provider` | `"beam" \| "stripe" \| null` | yes |
|
|
52
55
|
| `payments.methods` | `{ card: boolean, promptPay: boolean }` | yes |
|
|
53
56
|
|
|
54
57
|
- `plan.locations.included` is what the plan covers. `max` is a hard cap (the
|
|
55
58
|
entry plan has 1); `null` means no cap, and each location past `included` is
|
|
56
59
|
billed at `extraMonthly`. `included: null` means the number was agreed per deal.
|
|
60
|
+
- `pos.pro.locations` is how many locations the business pays for POS Pro (Edge
|
|
61
|
+
receipt printing, Bolt+ card terminals). `null` means no limit; `0` means none
|
|
62
|
+
(the entry plan never includes POS Pro). See "POS Pro hardware" below.
|
|
63
|
+
- `plan.accountingEdition` is the Accounting edition the business pays for, an
|
|
64
|
+
add-on next to its plan. `null` means it has no Accounting plan. See
|
|
65
|
+
"Accounting edition" below.
|
|
57
66
|
- Keys are never removed in later versions, so code written against today's list
|
|
58
67
|
keeps working.
|
|
59
68
|
|
|
69
|
+
## POS Pro hardware
|
|
70
|
+
|
|
71
|
+
Check `pos.pro` only when someone adds POS hardware (pairs a receipt printer or
|
|
72
|
+
a card terminal) at a location that has none yet. Never check it on a sale, a
|
|
73
|
+
print or a payment: hardware that is already set up keeps working whatever the
|
|
74
|
+
count says, so a business is never stopped mid-service.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const posPro = await getControl("pos.pro");
|
|
78
|
+
if (!posPro.ok) {
|
|
79
|
+
// Unknown right now: refuse the add with a retry message (answer 503), and
|
|
80
|
+
// leave the hardware the business already has alone.
|
|
81
|
+
return unavailable("POS Pro could not be checked. Try again in a minute.");
|
|
82
|
+
}
|
|
83
|
+
const { locations } = posPro.value;
|
|
84
|
+
const usesPosPro = await countLocationsWithPosHardware(); // locations with a printer or terminal
|
|
85
|
+
if (locations !== null && !locationAlreadyHasHardware && usesPosPro >= locations) {
|
|
86
|
+
return refuse("Every POS Pro location you pay for is in use. Add POS Pro to this location first.");
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A location that already has a printer or terminal can add more without using up
|
|
91
|
+
another POS Pro location.
|
|
92
|
+
|
|
93
|
+
## Accounting edition
|
|
94
|
+
|
|
95
|
+
Accounting comes in two editions, Small and Medium, each bought as an add-on.
|
|
96
|
+
Finance is on every plan and never depends on this control. Read
|
|
97
|
+
`plan.accountingEdition` to decide which Accounting the app offers:
|
|
98
|
+
|
|
99
|
+
- `"small"` or `"medium"`: offer that edition.
|
|
100
|
+
- `null`: the business has no Accounting plan. Hide Accounting and refuse its
|
|
101
|
+
writes with a message that it needs an Accounting plan. Records it made while
|
|
102
|
+
it had one stay readable.
|
|
103
|
+
- `ok: false`: unknown right now, which is not the same as `null`. Refuse new
|
|
104
|
+
accounting records (journal entries, period closes, filings) with a retry
|
|
105
|
+
message (answer 503), and keep everything that exists readable. Never hide
|
|
106
|
+
Accounting or treat the business as having none because of `ok: false`.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const edition = await getControl("plan.accountingEdition");
|
|
110
|
+
if (!edition.ok) {
|
|
111
|
+
return unavailable("Accounting could not be checked. Try again in a minute.");
|
|
112
|
+
}
|
|
113
|
+
if (edition.value === null) {
|
|
114
|
+
return refuse("Accounting needs an Accounting plan.");
|
|
115
|
+
}
|
|
116
|
+
// edition.value is "small" or "medium"
|
|
117
|
+
```
|
|
118
|
+
|
|
60
119
|
Types and the list itself are in the root export:
|
|
61
120
|
|
|
62
121
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -52,6 +52,22 @@ var CONTROLS = {
|
|
|
52
52
|
"payments.methods": {
|
|
53
53
|
schema: import_zod.z.object({ card: import_zod.z.boolean(), promptPay: import_zod.z.boolean() }),
|
|
54
54
|
appWrite: true
|
|
55
|
+
},
|
|
56
|
+
"pos.pro": {
|
|
57
|
+
schema: import_zod.z.object({
|
|
58
|
+
/** POS Pro locations paid for. null = unlimited (legacy plans, internal orgs). */
|
|
59
|
+
locations: import_zod.z.number().int().nonnegative().nullable()
|
|
60
|
+
}),
|
|
61
|
+
appWrite: false
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
65
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
66
|
+
* refuse new accounting records and keep existing ones readable.
|
|
67
|
+
*/
|
|
68
|
+
"plan.accountingEdition": {
|
|
69
|
+
schema: import_zod.z.enum(["small", "medium"]).nullable(),
|
|
70
|
+
appWrite: false
|
|
55
71
|
}
|
|
56
72
|
};
|
|
57
73
|
var CONTROL_KEYS = Object.keys(CONTROLS);
|
package/dist/index.d.cts
CHANGED
|
@@ -48,6 +48,24 @@ declare const CONTROLS: {
|
|
|
48
48
|
}, z.core.$strip>;
|
|
49
49
|
readonly appWrite: true;
|
|
50
50
|
};
|
|
51
|
+
readonly "pos.pro": {
|
|
52
|
+
readonly schema: z.ZodObject<{
|
|
53
|
+
locations: z.ZodNullable<z.ZodNumber>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
readonly appWrite: false;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
59
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
60
|
+
* refuse new accounting records and keep existing ones readable.
|
|
61
|
+
*/
|
|
62
|
+
readonly "plan.accountingEdition": {
|
|
63
|
+
readonly schema: z.ZodNullable<z.ZodEnum<{
|
|
64
|
+
small: "small";
|
|
65
|
+
medium: "medium";
|
|
66
|
+
}>>;
|
|
67
|
+
readonly appWrite: false;
|
|
68
|
+
};
|
|
51
69
|
};
|
|
52
70
|
type ControlKey = keyof typeof CONTROLS;
|
|
53
71
|
type ControlValue<K extends ControlKey> = z.infer<(typeof CONTROLS)[K]["schema"]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,24 @@ declare const CONTROLS: {
|
|
|
48
48
|
}, z.core.$strip>;
|
|
49
49
|
readonly appWrite: true;
|
|
50
50
|
};
|
|
51
|
+
readonly "pos.pro": {
|
|
52
|
+
readonly schema: z.ZodObject<{
|
|
53
|
+
locations: z.ZodNullable<z.ZodNumber>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
readonly appWrite: false;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
59
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
60
|
+
* refuse new accounting records and keep existing ones readable.
|
|
61
|
+
*/
|
|
62
|
+
readonly "plan.accountingEdition": {
|
|
63
|
+
readonly schema: z.ZodNullable<z.ZodEnum<{
|
|
64
|
+
small: "small";
|
|
65
|
+
medium: "medium";
|
|
66
|
+
}>>;
|
|
67
|
+
readonly appWrite: false;
|
|
68
|
+
};
|
|
51
69
|
};
|
|
52
70
|
type ControlKey = keyof typeof CONTROLS;
|
|
53
71
|
type ControlValue<K extends ControlKey> = z.infer<(typeof CONTROLS)[K]["schema"]>;
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,22 @@ var CONTROLS = {
|
|
|
21
21
|
"payments.methods": {
|
|
22
22
|
schema: z.object({ card: z.boolean(), promptPay: z.boolean() }),
|
|
23
23
|
appWrite: true
|
|
24
|
+
},
|
|
25
|
+
"pos.pro": {
|
|
26
|
+
schema: z.object({
|
|
27
|
+
/** POS Pro locations paid for. null = unlimited (legacy plans, internal orgs). */
|
|
28
|
+
locations: z.number().int().nonnegative().nullable()
|
|
29
|
+
}),
|
|
30
|
+
appWrite: false
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
34
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
35
|
+
* refuse new accounting records and keep existing ones readable.
|
|
36
|
+
*/
|
|
37
|
+
"plan.accountingEdition": {
|
|
38
|
+
schema: z.enum(["small", "medium"]).nullable(),
|
|
39
|
+
appWrite: false
|
|
24
40
|
}
|
|
25
41
|
};
|
|
26
42
|
var CONTROL_KEYS = Object.keys(CONTROLS);
|
package/dist/server/index.cjs
CHANGED
|
@@ -53,6 +53,22 @@ var CONTROLS = {
|
|
|
53
53
|
"payments.methods": {
|
|
54
54
|
schema: import_zod.z.object({ card: import_zod.z.boolean(), promptPay: import_zod.z.boolean() }),
|
|
55
55
|
appWrite: true
|
|
56
|
+
},
|
|
57
|
+
"pos.pro": {
|
|
58
|
+
schema: import_zod.z.object({
|
|
59
|
+
/** POS Pro locations paid for. null = unlimited (legacy plans, internal orgs). */
|
|
60
|
+
locations: import_zod.z.number().int().nonnegative().nullable()
|
|
61
|
+
}),
|
|
62
|
+
appWrite: false
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
66
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
67
|
+
* refuse new accounting records and keep existing ones readable.
|
|
68
|
+
*/
|
|
69
|
+
"plan.accountingEdition": {
|
|
70
|
+
schema: import_zod.z.enum(["small", "medium"]).nullable(),
|
|
71
|
+
appWrite: false
|
|
56
72
|
}
|
|
57
73
|
};
|
|
58
74
|
var CONTROL_KEYS = Object.keys(CONTROLS);
|
package/dist/server/index.d.cts
CHANGED
|
@@ -48,6 +48,24 @@ declare const CONTROLS: {
|
|
|
48
48
|
}, z.core.$strip>;
|
|
49
49
|
readonly appWrite: true;
|
|
50
50
|
};
|
|
51
|
+
readonly "pos.pro": {
|
|
52
|
+
readonly schema: z.ZodObject<{
|
|
53
|
+
locations: z.ZodNullable<z.ZodNumber>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
readonly appWrite: false;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
59
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
60
|
+
* refuse new accounting records and keep existing ones readable.
|
|
61
|
+
*/
|
|
62
|
+
readonly "plan.accountingEdition": {
|
|
63
|
+
readonly schema: z.ZodNullable<z.ZodEnum<{
|
|
64
|
+
small: "small";
|
|
65
|
+
medium: "medium";
|
|
66
|
+
}>>;
|
|
67
|
+
readonly appWrite: false;
|
|
68
|
+
};
|
|
51
69
|
};
|
|
52
70
|
type ControlKey = keyof typeof CONTROLS;
|
|
53
71
|
type ControlValue<K extends ControlKey> = z.infer<(typeof CONTROLS)[K]["schema"]>;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -48,6 +48,24 @@ declare const CONTROLS: {
|
|
|
48
48
|
}, z.core.$strip>;
|
|
49
49
|
readonly appWrite: true;
|
|
50
50
|
};
|
|
51
|
+
readonly "pos.pro": {
|
|
52
|
+
readonly schema: z.ZodObject<{
|
|
53
|
+
locations: z.ZodNullable<z.ZodNumber>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
readonly appWrite: false;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
59
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
60
|
+
* refuse new accounting records and keep existing ones readable.
|
|
61
|
+
*/
|
|
62
|
+
readonly "plan.accountingEdition": {
|
|
63
|
+
readonly schema: z.ZodNullable<z.ZodEnum<{
|
|
64
|
+
small: "small";
|
|
65
|
+
medium: "medium";
|
|
66
|
+
}>>;
|
|
67
|
+
readonly appWrite: false;
|
|
68
|
+
};
|
|
51
69
|
};
|
|
52
70
|
type ControlKey = keyof typeof CONTROLS;
|
|
53
71
|
type ControlValue<K extends ControlKey> = z.infer<(typeof CONTROLS)[K]["schema"]>;
|
package/dist/server/index.js
CHANGED
|
@@ -21,6 +21,22 @@ var CONTROLS = {
|
|
|
21
21
|
"payments.methods": {
|
|
22
22
|
schema: z.object({ card: z.boolean(), promptPay: z.boolean() }),
|
|
23
23
|
appWrite: true
|
|
24
|
+
},
|
|
25
|
+
"pos.pro": {
|
|
26
|
+
schema: z.object({
|
|
27
|
+
/** POS Pro locations paid for. null = unlimited (legacy plans, internal orgs). */
|
|
28
|
+
locations: z.number().int().nonnegative().nullable()
|
|
29
|
+
}),
|
|
30
|
+
appWrite: false
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* The Accounting Module edition the org pays for, each an add-on next to its plan. null means
|
|
34
|
+
* no Accounting plan: the app has no Accounting. `{ ok: false }` means unknown right now:
|
|
35
|
+
* refuse new accounting records and keep existing ones readable.
|
|
36
|
+
*/
|
|
37
|
+
"plan.accountingEdition": {
|
|
38
|
+
schema: z.enum(["small", "medium"]).nullable(),
|
|
39
|
+
appWrite: false
|
|
24
40
|
}
|
|
25
41
|
};
|
|
26
42
|
var CONTROL_KEYS = Object.keys(CONTROLS);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardeck-customer-apps/controls",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "Platform-owned app controls (feature flags, plan limits, payment provider and methods) for Stardeck customer apps: a typed list plus a cached, signed sync client",
|
|
4
|
+
"version": "0.3.0",
|
|
5
|
+
"description": "Platform-owned app controls (feature flags, plan limits, POS Pro hardware, the Accounting edition, payment provider and methods) for Stardeck customer apps: a typed list plus a cached, signed sync client",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|