@shipeasy/openapi 1.6.0 → 2.2.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.
Files changed (151) hide show
  1. package/README.md +37 -0
  2. package/dist/chunk-643YSMLU.js +1616 -0
  3. package/dist/chunk-643YSMLU.js.map +1 -0
  4. package/dist/chunk-MRW3DJ57.js +3385 -0
  5. package/dist/chunk-MRW3DJ57.js.map +1 -0
  6. package/dist/client-K0ShmsC7.d.ts +11284 -0
  7. package/dist/client.d.ts +1 -0
  8. package/dist/client.js +215 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/custom.d.ts +86 -0
  11. package/dist/custom.js +300 -0
  12. package/dist/custom.js.map +1 -0
  13. package/dist/index.d.ts +29 -41
  14. package/dist/index.js +258 -4375
  15. package/dist/index.js.map +1 -0
  16. package/dist/node-context.d.ts +81 -33
  17. package/dist/node-context.js +98 -44
  18. package/dist/node-context.js.map +1 -0
  19. package/dist/schemas.d.ts +7973 -0
  20. package/dist/schemas.js +1099 -0
  21. package/dist/schemas.js.map +1 -0
  22. package/openapi.json +15922 -3232
  23. package/openapi.yaml +14277 -0
  24. package/package.json +33 -26
  25. package/spec/components/errors.yaml +53 -0
  26. package/spec/components/parameters.yaml +32 -0
  27. package/spec/components/responses.yaml +122 -0
  28. package/spec/components/schemas/alert-rules.yaml +175 -0
  29. package/spec/components/schemas/attributes.yaml +157 -0
  30. package/spec/components/schemas/common.yaml +92 -0
  31. package/spec/components/schemas/configs.yaml +371 -0
  32. package/spec/components/schemas/connectors.yaml +587 -0
  33. package/spec/components/schemas/errors-api.yaml +209 -0
  34. package/spec/components/schemas/events.yaml +321 -0
  35. package/spec/components/schemas/experiments.yaml +865 -0
  36. package/spec/components/schemas/gate-templates.yaml +237 -0
  37. package/spec/components/schemas/gates.yaml +890 -0
  38. package/spec/components/schemas/i18n.yaml +478 -0
  39. package/spec/components/schemas/keys.yaml +186 -0
  40. package/spec/components/schemas/killswitches.yaml +309 -0
  41. package/spec/components/schemas/metrics.yaml +547 -0
  42. package/spec/components/schemas/ops.yaml +1013 -0
  43. package/spec/components/schemas/projects.yaml +222 -0
  44. package/spec/components/schemas/search.yaml +46 -0
  45. package/spec/components/schemas/universes.yaml +127 -0
  46. package/spec/openapi.yaml +367 -0
  47. package/spec/paths/alert-rules.yaml +258 -0
  48. package/spec/paths/attributes.yaml +272 -0
  49. package/spec/paths/configs.yaml +758 -0
  50. package/spec/paths/connectors.yaml +782 -0
  51. package/spec/paths/errors.yaml +382 -0
  52. package/spec/paths/events.yaml +380 -0
  53. package/spec/paths/experiments.yaml +803 -0
  54. package/spec/paths/gate-templates.yaml +267 -0
  55. package/spec/paths/gates.yaml +465 -0
  56. package/spec/paths/i18n.yaml +557 -0
  57. package/spec/paths/keys.yaml +182 -0
  58. package/spec/paths/killswitches.yaml +574 -0
  59. package/spec/paths/metrics.yaml +313 -0
  60. package/spec/paths/ops.yaml +446 -0
  61. package/spec/paths/projects.yaml +210 -0
  62. package/spec/paths/search.yaml +62 -0
  63. package/spec/paths/universes.yaml +255 -0
  64. package/dist/operations/attributes.d.ts +0 -33
  65. package/dist/operations/attributes.js +0 -16
  66. package/dist/operations/cli-adapter.d.ts +0 -35
  67. package/dist/operations/cli-adapter.js +0 -91
  68. package/dist/operations/coerce.d.ts +0 -32
  69. package/dist/operations/coerce.js +0 -53
  70. package/dist/operations/configs.d.ts +0 -28
  71. package/dist/operations/configs.js +0 -119
  72. package/dist/operations/docs.d.ts +0 -37
  73. package/dist/operations/docs.js +0 -39
  74. package/dist/operations/events.d.ts +0 -28
  75. package/dist/operations/events.js +0 -121
  76. package/dist/operations/experiments.d.ts +0 -28
  77. package/dist/operations/experiments.js +0 -280
  78. package/dist/operations/gates.d.ts +0 -28
  79. package/dist/operations/gates.js +0 -132
  80. package/dist/operations/i18n.d.ts +0 -28
  81. package/dist/operations/i18n.js +0 -121
  82. package/dist/operations/index.d.ts +0 -63
  83. package/dist/operations/index.js +0 -1751
  84. package/dist/operations/killswitches.d.ts +0 -28
  85. package/dist/operations/killswitches.js +0 -126
  86. package/dist/operations/mcp-adapter.d.ts +0 -35
  87. package/dist/operations/mcp-adapter.js +0 -94
  88. package/dist/operations/metrics.d.ts +0 -30
  89. package/dist/operations/metrics.js +0 -114
  90. package/dist/operations/ops.d.ts +0 -28
  91. package/dist/operations/ops.js +0 -313
  92. package/dist/operations/projects.d.ts +0 -28
  93. package/dist/operations/projects.js +0 -36
  94. package/dist/operations/sdk-docs.d.ts +0 -28
  95. package/dist/operations/sdk-docs.js +0 -160
  96. package/dist/operations/types.d.ts +0 -138
  97. package/dist/operations/types.js +0 -9
  98. package/dist/operations/universes.d.ts +0 -28
  99. package/dist/operations/universes.js +0 -93
  100. package/dist/operations/util.d.ts +0 -33
  101. package/dist/operations/util.js +0 -9
  102. package/dist/resources/alert-rules.d.ts +0 -50
  103. package/dist/resources/alert-rules.js +0 -75
  104. package/dist/resources/attributes.d.ts +0 -19
  105. package/dist/resources/attributes.js +0 -10
  106. package/dist/resources/configs.d.ts +0 -681
  107. package/dist/resources/configs.js +0 -509
  108. package/dist/resources/events.d.ts +0 -61
  109. package/dist/resources/events.js +0 -42
  110. package/dist/resources/experiments.d.ts +0 -849
  111. package/dist/resources/experiments.js +0 -707
  112. package/dist/resources/gates.d.ts +0 -808
  113. package/dist/resources/gates.js +0 -522
  114. package/dist/resources/i18n.d.ts +0 -84
  115. package/dist/resources/i18n.js +0 -60
  116. package/dist/resources/index.d.ts +0 -2767
  117. package/dist/resources/index.js +0 -2563
  118. package/dist/resources/killswitches.d.ts +0 -436
  119. package/dist/resources/killswitches.js +0 -514
  120. package/dist/resources/metrics.d.ts +0 -54
  121. package/dist/resources/metrics.js +0 -40
  122. package/dist/resources/ops.d.ts +0 -88
  123. package/dist/resources/ops.js +0 -36
  124. package/dist/resources/projects.d.ts +0 -54
  125. package/dist/resources/projects.js +0 -14
  126. package/dist/resources/universes.d.ts +0 -185
  127. package/dist/resources/universes.js +0 -234
  128. package/dist/schemas/alert-rules.d.ts +0 -65
  129. package/dist/schemas/alert-rules.js +0 -37
  130. package/dist/schemas/configs.d.ts +0 -154
  131. package/dist/schemas/configs.js +0 -134
  132. package/dist/schemas/constants.d.ts +0 -6
  133. package/dist/schemas/constants.js +0 -7
  134. package/dist/schemas/experiments.d.ts +0 -229
  135. package/dist/schemas/experiments.js +0 -221
  136. package/dist/schemas/folder.d.ts +0 -10
  137. package/dist/schemas/folder.js +0 -8
  138. package/dist/schemas/gates.d.ts +0 -386
  139. package/dist/schemas/gates.js +0 -190
  140. package/dist/schemas/index.d.ts +0 -11
  141. package/dist/schemas/index.js +0 -762
  142. package/dist/schemas/killswitches.d.ts +0 -110
  143. package/dist/schemas/killswitches.js +0 -226
  144. package/dist/schemas/metric-name.d.ts +0 -5
  145. package/dist/schemas/metric-name.js +0 -6
  146. package/dist/schemas/pagination.d.ts +0 -37
  147. package/dist/schemas/pagination.js +0 -44
  148. package/dist/schemas/universes.d.ts +0 -35
  149. package/dist/schemas/universes.js +0 -55
  150. package/dist/transport.d.ts +0 -30
  151. package/dist/transport.js +0 -44
@@ -0,0 +1 @@
1
+ export { i as Client, k as Config, m as ConfigureOptions, L as CreateClientConfig, gM as Options, hh as RequestResult, kA as approveEvent, kB as client, kC as configure, kD as createAlertRule, kE as createAttribute, kF as createClient, kG as createClientConfig, kH as createConfig, kI as createConnector, kJ as createEvent, kK as createExperiment, kL as createGate, kM as createGateTemplate, kN as createI18nDraft, kO as createI18nProfile, kP as createKey, kQ as createKillswitch, kR as createMetric, kS as createOpsItem, kT as createTriggerConnector, kU as createUniverse, kV as deleteAlertRule, kW as deleteAttribute, kX as deleteConfig, kY as deleteConnector, kZ as deleteEvent, k_ as deleteExperiment, k$ as deleteGate, l0 as deleteGateTemplate, l1 as deleteKillswitch, l2 as deleteMetric, l3 as deleteUniverse, l4 as disableGate, l5 as discardConfigDraft, l6 as enableGate, l7 as fileErrorTicket, l8 as fireConnector, l9 as getAttribute, la as getConfig, lb as getConnector, lc as getCurrentProject, ld as getError, le as getErrorSeries, lf as getEvent, lg as getExperiment, lh as getExperimentResults, li as getExperimentTimeseries, lj as getGateTemplate, lk as getKillswitch, ll as getMetric, lm as getOpsItem, ln as linkPrToOpsItem, lo as listAlertRules, lp as listAttributes, lq as listConfigActivity, lr as listConfigs, ls as listConnectors, lt as listErrors, lu as listEvents, lv as listExperiments, lw as listGateTemplates, lx as listGates, ly as listI18nDrafts, lz as listI18nKeys, lA as listI18nProfiles, lB as listKeys, lC as listKillswitches, lD as listMetrics, lE as listOpsItems, lF as listSlackChannels, lG as listUniverses, lH as notifyOps, lI as publishConfigDraft, lJ as publishI18nProfile, lK as pushI18nKeys, lL as reanalyzeExperiment, lM as revokeKey, lN as saveConfigDraft, lO as searchResources, lP as setExperimentMetrics, lQ as setExperimentStatus, lR as setI18nLabel, lS as setKillswitchSwitch, lT as setKillswitchValue, lU as testConnector, lV as unsetKillswitchSwitch, lW as updateAlertRule, lX as updateAttribute, lY as updateConfig, lZ as updateConfigSchema, l_ as updateConnector, l$ as updateErrorStatus, m0 as updateEvent, m1 as updateExperiment, m2 as updateGate, m3 as updateGateTemplate, m4 as updateI18nDraft, m5 as updateI18nKey, m6 as updateKillswitch, m7 as updateMetric, m8 as updateOpsItem, m9 as updateProject, ma as updateTriggerConnector, mb as updateUniverse, mc as upsertProject } from './client-K0ShmsC7.js';
package/dist/client.js ADDED
@@ -0,0 +1,215 @@
1
+ import {
2
+ approveEvent,
3
+ client,
4
+ configure,
5
+ createAlertRule,
6
+ createAttribute,
7
+ createClient,
8
+ createConfig,
9
+ createConfig2,
10
+ createConnector,
11
+ createEvent,
12
+ createExperiment,
13
+ createGate,
14
+ createGateTemplate,
15
+ createI18nDraft,
16
+ createI18nProfile,
17
+ createKey,
18
+ createKillswitch,
19
+ createMetric,
20
+ createOpsItem,
21
+ createTriggerConnector,
22
+ createUniverse,
23
+ deleteAlertRule,
24
+ deleteAttribute,
25
+ deleteConfig,
26
+ deleteConnector,
27
+ deleteEvent,
28
+ deleteExperiment,
29
+ deleteGate,
30
+ deleteGateTemplate,
31
+ deleteKillswitch,
32
+ deleteMetric,
33
+ deleteUniverse,
34
+ disableGate,
35
+ discardConfigDraft,
36
+ enableGate,
37
+ fileErrorTicket,
38
+ fireConnector,
39
+ getAttribute,
40
+ getConfig,
41
+ getConnector,
42
+ getCurrentProject,
43
+ getError,
44
+ getErrorSeries,
45
+ getEvent,
46
+ getExperiment,
47
+ getExperimentResults,
48
+ getExperimentTimeseries,
49
+ getGateTemplate,
50
+ getKillswitch,
51
+ getMetric,
52
+ getOpsItem,
53
+ linkPrToOpsItem,
54
+ listAlertRules,
55
+ listAttributes,
56
+ listConfigActivity,
57
+ listConfigs,
58
+ listConnectors,
59
+ listErrors,
60
+ listEvents,
61
+ listExperiments,
62
+ listGateTemplates,
63
+ listGates,
64
+ listI18nDrafts,
65
+ listI18nKeys,
66
+ listI18nProfiles,
67
+ listKeys,
68
+ listKillswitches,
69
+ listMetrics,
70
+ listOpsItems,
71
+ listSlackChannels,
72
+ listUniverses,
73
+ notifyOps,
74
+ publishConfigDraft,
75
+ publishI18nProfile,
76
+ pushI18nKeys,
77
+ reanalyzeExperiment,
78
+ revokeKey,
79
+ saveConfigDraft,
80
+ searchResources,
81
+ setExperimentMetrics,
82
+ setExperimentStatus,
83
+ setI18nLabel,
84
+ setKillswitchSwitch,
85
+ setKillswitchValue,
86
+ testConnector,
87
+ unsetKillswitchSwitch,
88
+ updateAlertRule,
89
+ updateAttribute,
90
+ updateConfig,
91
+ updateConfigSchema,
92
+ updateConnector,
93
+ updateErrorStatus,
94
+ updateEvent,
95
+ updateExperiment,
96
+ updateGate,
97
+ updateGateTemplate,
98
+ updateI18nDraft,
99
+ updateI18nKey,
100
+ updateKillswitch,
101
+ updateMetric,
102
+ updateOpsItem,
103
+ updateProject,
104
+ updateTriggerConnector,
105
+ updateUniverse,
106
+ upsertProject
107
+ } from "./chunk-643YSMLU.js";
108
+ export {
109
+ approveEvent,
110
+ client,
111
+ configure,
112
+ createAlertRule,
113
+ createAttribute,
114
+ createClient,
115
+ createConfig as createClientConfig,
116
+ createConfig2 as createConfig,
117
+ createConnector,
118
+ createEvent,
119
+ createExperiment,
120
+ createGate,
121
+ createGateTemplate,
122
+ createI18nDraft,
123
+ createI18nProfile,
124
+ createKey,
125
+ createKillswitch,
126
+ createMetric,
127
+ createOpsItem,
128
+ createTriggerConnector,
129
+ createUniverse,
130
+ deleteAlertRule,
131
+ deleteAttribute,
132
+ deleteConfig,
133
+ deleteConnector,
134
+ deleteEvent,
135
+ deleteExperiment,
136
+ deleteGate,
137
+ deleteGateTemplate,
138
+ deleteKillswitch,
139
+ deleteMetric,
140
+ deleteUniverse,
141
+ disableGate,
142
+ discardConfigDraft,
143
+ enableGate,
144
+ fileErrorTicket,
145
+ fireConnector,
146
+ getAttribute,
147
+ getConfig,
148
+ getConnector,
149
+ getCurrentProject,
150
+ getError,
151
+ getErrorSeries,
152
+ getEvent,
153
+ getExperiment,
154
+ getExperimentResults,
155
+ getExperimentTimeseries,
156
+ getGateTemplate,
157
+ getKillswitch,
158
+ getMetric,
159
+ getOpsItem,
160
+ linkPrToOpsItem,
161
+ listAlertRules,
162
+ listAttributes,
163
+ listConfigActivity,
164
+ listConfigs,
165
+ listConnectors,
166
+ listErrors,
167
+ listEvents,
168
+ listExperiments,
169
+ listGateTemplates,
170
+ listGates,
171
+ listI18nDrafts,
172
+ listI18nKeys,
173
+ listI18nProfiles,
174
+ listKeys,
175
+ listKillswitches,
176
+ listMetrics,
177
+ listOpsItems,
178
+ listSlackChannels,
179
+ listUniverses,
180
+ notifyOps,
181
+ publishConfigDraft,
182
+ publishI18nProfile,
183
+ pushI18nKeys,
184
+ reanalyzeExperiment,
185
+ revokeKey,
186
+ saveConfigDraft,
187
+ searchResources,
188
+ setExperimentMetrics,
189
+ setExperimentStatus,
190
+ setI18nLabel,
191
+ setKillswitchSwitch,
192
+ setKillswitchValue,
193
+ testConnector,
194
+ unsetKillswitchSwitch,
195
+ updateAlertRule,
196
+ updateAttribute,
197
+ updateConfig,
198
+ updateConfigSchema,
199
+ updateConnector,
200
+ updateErrorStatus,
201
+ updateEvent,
202
+ updateExperiment,
203
+ updateGate,
204
+ updateGateTemplate,
205
+ updateI18nDraft,
206
+ updateI18nKey,
207
+ updateKillswitch,
208
+ updateMetric,
209
+ updateOpsItem,
210
+ updateProject,
211
+ updateTriggerConnector,
212
+ updateUniverse,
213
+ upsertProject
214
+ };
215
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The custom-operations registry — hand-written operations that are NOT admin
3
+ * API endpoints (so they can't be generated from the spec): the metric-DSL
4
+ * grammar (pure) and the SDK-docs fetcher (outbound `fetch` to GitHub Pages).
5
+ *
6
+ * It mirrors the old operations registry in spirit, but is deliberately tiny and
7
+ * framework-agnostic: each `CustomOp` carries its command path, params, and a
8
+ * self-contained `run`. Both consumers project it with a thin adapter — the CLI
9
+ * (`commands/custom.ts`) and, later, the MCP server — so the surface stays in
10
+ * sync across them. `run` never touches the filesystem, so it's worker-safe.
11
+ */
12
+ type CustomParamType = "string" | "number" | "boolean";
13
+ interface CustomParam {
14
+ name: string;
15
+ type: CustomParamType;
16
+ description?: string;
17
+ required?: boolean;
18
+ /** Render as a positional CLI argument (vs a `--flag`). */
19
+ positional?: boolean;
20
+ enum?: string[];
21
+ }
22
+ interface CustomOp {
23
+ /** Command path, e.g. `["docs"]` → `shipeasy docs <name>`, `["metrics"]` → `metrics <name>`. */
24
+ group: string[];
25
+ /** Verb. */
26
+ name: string;
27
+ summary: string;
28
+ description?: string;
29
+ params: CustomParam[];
30
+ examples?: {
31
+ note?: string;
32
+ run: string;
33
+ }[];
34
+ /** Self-contained handler. `args` are the coerced param values. */
35
+ run: (args: Record<string, unknown>) => Promise<unknown> | unknown;
36
+ }
37
+ /**
38
+ * Group-level help for a custom-op command group (e.g. `docs`). Mirrors what an
39
+ * OpenAPI tag carries for the generated tree — a short `summary` (shown in the
40
+ * parent `--help` list) and a long `description` (shown on the group's own
41
+ * `--help`). Consumers look this up by `group` path when creating the group so a
42
+ * custom group reads as richly as a spec-backed one, instead of the bare
43
+ * `"<name> commands"` fallback.
44
+ */
45
+ interface CustomGroup {
46
+ /** Group path, e.g. `["docs"]`. */
47
+ group: string[];
48
+ summary: string;
49
+ description?: string;
50
+ aliases?: string[];
51
+ }
52
+ /** Thrown by a custom op for a user-facing error with an HTTP-ish status. */
53
+ declare class CustomOpError extends Error {
54
+ status: number;
55
+ constructor(message: string, status?: number);
56
+ }
57
+ declare const opId: (op: CustomOp) => string;
58
+
59
+ /**
60
+ * The Shipeasy metric query DSL grammar — printed by `shipeasy metrics grammar`
61
+ * / the `metrics_grammar` MCP tool.
62
+ *
63
+ * This is the one-stop reference for both humans and AI agents that need to
64
+ * author a `metrics create --query "..."` string. It is intentionally
65
+ * self-contained: the formal grammar (precise, for machine parsing), a full
66
+ * aggregation reference (semantics + value-label rules + experiment behaviour),
67
+ * the selector/filter/group-by rules, hard constraints, and glossed examples.
68
+ * Keep it in sync with the parser (`cli/src/query-dsl/parse.ts`) and the IR
69
+ * (`cli/src/query-dsl/ir.ts`) — they are the source of truth for semantics.
70
+ */
71
+ declare const METRIC_GRAMMAR = "SHIPEASY METRIC QUERY DSL\n=========================\n\nA metric is ONE aggregation over ONE event stream. This DSL is the string you\npass to `metrics create --query \"...\"` (equivalently the typed `query_ir`).\nThere is no arithmetic, no formulas across events, no subqueries \u2014 one event\nselector, one aggregation, an optional group-by.\n\n\nGRAMMAR (BNF)\n-------------\n Query := AggFunc \"(\" Selector (\",\" Identifier)? \")\" GroupBy?\n AggFunc := \"count_users\" | \"count\" | \"sum\" | \"avg\" | \"min\" | \"max\"\n | \"unique\" | \"p50\" | \"p75\" | \"p90\" | \"p95\" | \"p99\" | \"p999\"\n | \"retention_\" <N> \"d\" (N = 1..90)\n Selector := Identifier (\"{\" Filter (\",\" Filter)* \",\"? \"}\")?\n Filter := Identifier MatchOp StringLiteral\n MatchOp := \"=\" | \"!=\" | \"=~\" | \"!~\"\n GroupBy := (\"by\" | \"without\") \"(\" Identifier (\",\" Identifier)* \",\"? \")\"\n StringLiteral := double-quoted; \\\" is a literal quote, \\\\ is a backslash\n Identifier := [A-Za-z_][A-Za-z0-9_]* (case-sensitive)\n\n The trailing Identifier after the selector \u2014 \"(\" Selector \",\" Identifier \")\" \u2014\n is the VALUE LABEL: the numeric event label the aggregation reduces. Whether it\n is required, optional, or forbidden depends on the aggregation (see below).\n\n\nAGGREGATIONS\n------------\n Function Value label Meaning In experiments\n -------------- ------------ ------------------------------ ---------------\n count_users forbidden distinct users who fired it exact\n count forbidden number of events (rows) exact\n sum(e, v) required \u03A3 of numeric label v exact\n avg(e, v) required mean of label v exact\n retention_Nd(e) forbidden % of users who returned exact\n within N days (N = 1..90)\n min(e, v) required minimum of label v approx \u2192 avg *\n max(e, v) required maximum of label v approx \u2192 avg *\n unique(e, v) required distinct values of label v approx \u2192 avg *\n p50 \u2026 p999(e,v) required quantile of v (50/75/90/ approx \u2192 avg *\n 95/99/99.9th percentile)\n\n * Display-only aggregations. The experiment t-test needs a per-user mean and\n variance, so min/max/unique/quantile are computed exactly on dashboards but\n collapse to a per-user `avg` when used as an experiment metric. If you need\n an exact experiment metric, pick count_users / count / sum / avg / retention.\n\n \"count\" is the DSL spelling of the internal count_events (one per matching\n row); \"count_users\" is unique-by-user. Getting these two confused is the most\n common mistake \u2014 count double-counts a user who fired the event twice.\n\n\nSELECTOR & FILTERS\n------------------\n The selector is the event name plus an optional `{ ... }` filter set that\n narrows which events count. Each filter compares an event LABEL to a quoted\n string:\n\n = equal != not equal\n =~ regex match !~ regex NOT match\n\n - Values are ALWAYS double-quoted strings, even for numeric labels \u2014 they are\n coerced on the server (`amount=~\"^1[0-9]$\"`, `status=\"200\"`).\n - Multiple filters are AND-ed: `{country=\"US\", tier!=\"free\"}`.\n - Every filter label AND the value label must be a label DECLARED on the source\n event. Undeclared labels are a validation error, not a silent no-match.\n\n\nGROUP-BY\n--------\n Splits the result into one series per label combination.\n by (a, b) one series per distinct (a, b) \u2014 keep only these labels\n without (a, b) group by all declared labels EXCEPT a, b\n\n NOTE: group-by is a DASHBOARD-only feature. In an experiment the group-by is\n ignored \u2014 a per-user reducer is applied across the whole arm instead.\n\n\nNOT SUPPORTED (will fail to parse)\n----------------------------------\n - arithmetic / ratios / formulas: `count(a) / count(b)`\n - more than one event per query\n - arbitrary quantiles (only the fixed p50/p75/p90/p95/p99/p999)\n - unquoted or numeric filter values: `{status=200}` \u2192 must be `\"200\"`\n - trailing tokens after the query\n\n\nEXAMPLES (query \u2014 what it measures)\n--------------------------------------\n count_users(checkout_completed)\n distinct users who completed checkout.\n\n count(add_to_cart{country=\"US\"})\n number of US add-to-cart events (a user can count many times).\n\n sum(purchase{country=\"US\"}, amount)\n total purchase amount from US purchase events.\n\n avg(req_dur{tier!=\"free\"}, ms) without (region)\n mean request duration for non-free tiers, one series per region-excluded\n label combination.\n\n p99(req_dur{route=~\"/api/.*\"}, ms) by (route, status)\n 99th-percentile latency of /api/* requests, split by route and status.\n\n unique(login{method=\"sso\"}, device_id)\n distinct SSO devices seen (display-only; an experiment would use per-user avg).\n\n retention_7d(session_start)\n share of users who started a new session within 7 days.\n";
72
+
73
+ /**
74
+ * Every custom (non-spec) operation, in surface order. The CLI and MCP each
75
+ * project this with a thin adapter so the sugar commands stay in sync.
76
+ */
77
+ declare const customOperations: CustomOp[];
78
+ /**
79
+ * Group-level help for custom-op groups that aren't backed by an OpenAPI tag.
80
+ * `metrics` is a spec tag (its group is created — and described — by the
81
+ * generated tree), so only `docs` needs an entry here; without it the CLI would
82
+ * label the group the bare `"docs commands"`.
83
+ */
84
+ declare const customGroups: CustomGroup[];
85
+
86
+ export { type CustomGroup, type CustomOp, CustomOpError, type CustomParam, type CustomParamType, METRIC_GRAMMAR, customGroups, customOperations, opId };
package/dist/custom.js ADDED
@@ -0,0 +1,300 @@
1
+ // src/custom/grammar.ts
2
+ var METRIC_GRAMMAR = `SHIPEASY METRIC QUERY DSL
3
+ =========================
4
+
5
+ A metric is ONE aggregation over ONE event stream. This DSL is the string you
6
+ pass to \`metrics create --query "..."\` (equivalently the typed \`query_ir\`).
7
+ There is no arithmetic, no formulas across events, no subqueries \u2014 one event
8
+ selector, one aggregation, an optional group-by.
9
+
10
+
11
+ GRAMMAR (BNF)
12
+ -------------
13
+ Query := AggFunc "(" Selector ("," Identifier)? ")" GroupBy?
14
+ AggFunc := "count_users" | "count" | "sum" | "avg" | "min" | "max"
15
+ | "unique" | "p50" | "p75" | "p90" | "p95" | "p99" | "p999"
16
+ | "retention_" <N> "d" (N = 1..90)
17
+ Selector := Identifier ("{" Filter ("," Filter)* ","? "}")?
18
+ Filter := Identifier MatchOp StringLiteral
19
+ MatchOp := "=" | "!=" | "=~" | "!~"
20
+ GroupBy := ("by" | "without") "(" Identifier ("," Identifier)* ","? ")"
21
+ StringLiteral := double-quoted; \\" is a literal quote, \\\\ is a backslash
22
+ Identifier := [A-Za-z_][A-Za-z0-9_]* (case-sensitive)
23
+
24
+ The trailing Identifier after the selector \u2014 "(" Selector "," Identifier ")" \u2014
25
+ is the VALUE LABEL: the numeric event label the aggregation reduces. Whether it
26
+ is required, optional, or forbidden depends on the aggregation (see below).
27
+
28
+
29
+ AGGREGATIONS
30
+ ------------
31
+ Function Value label Meaning In experiments
32
+ -------------- ------------ ------------------------------ ---------------
33
+ count_users forbidden distinct users who fired it exact
34
+ count forbidden number of events (rows) exact
35
+ sum(e, v) required \u03A3 of numeric label v exact
36
+ avg(e, v) required mean of label v exact
37
+ retention_Nd(e) forbidden % of users who returned exact
38
+ within N days (N = 1..90)
39
+ min(e, v) required minimum of label v approx \u2192 avg *
40
+ max(e, v) required maximum of label v approx \u2192 avg *
41
+ unique(e, v) required distinct values of label v approx \u2192 avg *
42
+ p50 \u2026 p999(e,v) required quantile of v (50/75/90/ approx \u2192 avg *
43
+ 95/99/99.9th percentile)
44
+
45
+ * Display-only aggregations. The experiment t-test needs a per-user mean and
46
+ variance, so min/max/unique/quantile are computed exactly on dashboards but
47
+ collapse to a per-user \`avg\` when used as an experiment metric. If you need
48
+ an exact experiment metric, pick count_users / count / sum / avg / retention.
49
+
50
+ "count" is the DSL spelling of the internal count_events (one per matching
51
+ row); "count_users" is unique-by-user. Getting these two confused is the most
52
+ common mistake \u2014 count double-counts a user who fired the event twice.
53
+
54
+
55
+ SELECTOR & FILTERS
56
+ ------------------
57
+ The selector is the event name plus an optional \`{ ... }\` filter set that
58
+ narrows which events count. Each filter compares an event LABEL to a quoted
59
+ string:
60
+
61
+ = equal != not equal
62
+ =~ regex match !~ regex NOT match
63
+
64
+ - Values are ALWAYS double-quoted strings, even for numeric labels \u2014 they are
65
+ coerced on the server (\`amount=~"^1[0-9]$"\`, \`status="200"\`).
66
+ - Multiple filters are AND-ed: \`{country="US", tier!="free"}\`.
67
+ - Every filter label AND the value label must be a label DECLARED on the source
68
+ event. Undeclared labels are a validation error, not a silent no-match.
69
+
70
+
71
+ GROUP-BY
72
+ --------
73
+ Splits the result into one series per label combination.
74
+ by (a, b) one series per distinct (a, b) \u2014 keep only these labels
75
+ without (a, b) group by all declared labels EXCEPT a, b
76
+
77
+ NOTE: group-by is a DASHBOARD-only feature. In an experiment the group-by is
78
+ ignored \u2014 a per-user reducer is applied across the whole arm instead.
79
+
80
+
81
+ NOT SUPPORTED (will fail to parse)
82
+ ----------------------------------
83
+ - arithmetic / ratios / formulas: \`count(a) / count(b)\`
84
+ - more than one event per query
85
+ - arbitrary quantiles (only the fixed p50/p75/p90/p95/p99/p999)
86
+ - unquoted or numeric filter values: \`{status=200}\` \u2192 must be \`"200"\`
87
+ - trailing tokens after the query
88
+
89
+
90
+ EXAMPLES (query \u2014 what it measures)
91
+ --------------------------------------
92
+ count_users(checkout_completed)
93
+ distinct users who completed checkout.
94
+
95
+ count(add_to_cart{country="US"})
96
+ number of US add-to-cart events (a user can count many times).
97
+
98
+ sum(purchase{country="US"}, amount)
99
+ total purchase amount from US purchase events.
100
+
101
+ avg(req_dur{tier!="free"}, ms) without (region)
102
+ mean request duration for non-free tiers, one series per region-excluded
103
+ label combination.
104
+
105
+ p99(req_dur{route=~"/api/.*"}, ms) by (route, status)
106
+ 99th-percentile latency of /api/* requests, split by route and status.
107
+
108
+ unique(login{method="sso"}, device_id)
109
+ distinct SSO devices seen (display-only; an experiment would use per-user avg).
110
+
111
+ retention_7d(session_start)
112
+ share of users who started a new session within 7 days.
113
+ `;
114
+ var grammarOp = {
115
+ group: ["metrics"],
116
+ name: "grammar",
117
+ summary: "Print the metric query DSL grammar",
118
+ description: "Print the full metric query DSL reference \u2014 grammar, aggregation semantics, filter/group-by rules, and glossed examples \u2014 used to author `metrics create --query`.",
119
+ params: [],
120
+ examples: [{ run: "shipeasy metrics grammar" }],
121
+ run: () => ({ grammar: METRIC_GRAMMAR })
122
+ };
123
+
124
+ // src/custom/types.ts
125
+ var CustomOpError = class extends Error {
126
+ constructor(message, status = 400) {
127
+ super(message);
128
+ this.status = status;
129
+ this.name = "CustomOpError";
130
+ }
131
+ status;
132
+ };
133
+ var opId = (op) => [...op.group, op.name].join(".");
134
+
135
+ // src/custom/docs.ts
136
+ var SDK_REPOS = {
137
+ typescript: { owner: "shipeasy-ai", repo: "sdk" },
138
+ javascript: { owner: "shipeasy-ai", repo: "sdk" },
139
+ node: { owner: "shipeasy-ai", repo: "sdk" },
140
+ ts: { owner: "shipeasy-ai", repo: "sdk" },
141
+ python: { owner: "shipeasy-ai", repo: "sdk-python" },
142
+ go: { owner: "shipeasy-ai", repo: "sdk-go" },
143
+ java: { owner: "shipeasy-ai", repo: "sdk-java" },
144
+ kotlin: { owner: "shipeasy-ai", repo: "sdk-kotlin" },
145
+ php: { owner: "shipeasy-ai", repo: "sdk-php" },
146
+ swift: { owner: "shipeasy-ai", repo: "sdk-swift" },
147
+ ruby: { owner: "shipeasy-ai", repo: "sdk-ruby" }
148
+ };
149
+ var SDK_ENUM = Object.keys(SDK_REPOS);
150
+ var DEFAULT_MANIFEST = {
151
+ schemaVersion: 2,
152
+ sdk: "default",
153
+ placeholders: ["RESOURCE_NAME"],
154
+ skill: "skill/SKILL.md",
155
+ pages: { overview: "pages/overview.md", installation: "pages/installation.md" },
156
+ snippets: { release: { flags: "snippets/release/flags.md" } }
157
+ };
158
+ var DEFAULT_CONTENT = {
159
+ "pages/overview.md": "# Shipeasy SDK\n\nThis SDK has not published its `/docs/` folder yet. See https://docs.shipeasy.ai for the full reference.",
160
+ "pages/installation.md": "# Installation\n\nInstall the Shipeasy SDK for your language, then call `shipeasy({ serverKey })` (server) or `shipeasy({ clientKey })` (browser).",
161
+ "snippets/release/flags.md": "```\nconst on = await client.checkGate(user, '{{RESOURCE_NAME}}');\n```",
162
+ "skill/SKILL.md": "---\nname: shipeasy-sdk\ndescription: Use the Shipeasy SDK for flags, experiments, configs, and i18n.\n---\n\nThis SDK has not published a skill yet. See https://docs.shipeasy.ai."
163
+ };
164
+ function requireSdk(sdk) {
165
+ const s = typeof sdk === "string" ? sdk.trim() : "";
166
+ if (!s)
167
+ throw new CustomOpError(
168
+ `No SDK given and none recorded in .shipeasy. Pass --sdk <lang> (one of: ${SDK_ENUM.join(", ")}), or run \`shipeasy detect\` in the project to record its sdk.`,
169
+ 400
170
+ );
171
+ return s;
172
+ }
173
+ function repoFor(sdk) {
174
+ const r = SDK_REPOS[sdk.toLowerCase()];
175
+ if (!r) throw new CustomOpError(`Unknown SDK '${sdk}'. One of: ${SDK_ENUM.join(", ")}`, 400);
176
+ return r;
177
+ }
178
+ function pagesBase(sdk) {
179
+ const { owner, repo } = repoFor(sdk);
180
+ return `https://${owner}.github.io/${repo}`;
181
+ }
182
+ async function fetchText(url) {
183
+ const res = await fetch(url);
184
+ if (!res.ok) return null;
185
+ return res.text();
186
+ }
187
+ async function loadManifest(sdk) {
188
+ const text = await fetchText(`${pagesBase(sdk)}/manifest.json`);
189
+ if (!text) return { manifest: DEFAULT_MANIFEST, fallback: true };
190
+ try {
191
+ return { manifest: JSON.parse(text), fallback: false };
192
+ } catch {
193
+ return { manifest: DEFAULT_MANIFEST, fallback: true };
194
+ }
195
+ }
196
+ function resolvePath(manifest, handle) {
197
+ if (handle.endsWith(".md")) return handle;
198
+ if (manifest.pages?.[handle]) return manifest.pages[handle];
199
+ if (handle.includes("/")) {
200
+ const [group, resource] = handle.split("/", 2);
201
+ const p = manifest.snippets?.[group]?.[resource];
202
+ if (p) return p;
203
+ }
204
+ throw new CustomOpError(
205
+ `Doc '${handle}' not found. Run 'docs list --sdk <lang>' to see available pages and snippets.`,
206
+ 404
207
+ );
208
+ }
209
+ function substitute(body, manifest, args) {
210
+ let out = body;
211
+ for (const ph of manifest.placeholders ?? []) {
212
+ const value = args[ph] ?? (ph === "RESOURCE_NAME" ? args.name : void 0) ?? (ph === "FRAMEWORK" ? args.framework : void 0);
213
+ if (value !== void 0) out = out.replaceAll(`{{${ph}}}`, value);
214
+ }
215
+ return out;
216
+ }
217
+ var docsOps = [
218
+ {
219
+ group: ["docs"],
220
+ name: "list",
221
+ summary: "List an SDK's documentation tree",
222
+ description: "Fetch an SDK's `/docs/manifest.json` and return the doc tree \u2014 feature pages, nested snippet groups, and whether an installable skill exists.",
223
+ params: [{ name: "sdk", type: "string", description: "SDK language. Defaults to the `sdk` recorded in the nearest `.shipeasy` when omitted.", required: false, enum: SDK_ENUM }],
224
+ examples: [{ run: "shipeasy docs list --sdk python" }],
225
+ run: async (args) => {
226
+ const sdk = requireSdk(args.sdk);
227
+ const { manifest, fallback } = await loadManifest(sdk);
228
+ return {
229
+ sdk,
230
+ fallback,
231
+ pages: Object.keys(manifest.pages ?? {}),
232
+ snippets: Object.fromEntries(
233
+ Object.entries(manifest.snippets ?? {}).map(([g, r]) => [g, Object.keys(r)])
234
+ ),
235
+ skill: Boolean(manifest.skill)
236
+ };
237
+ }
238
+ },
239
+ {
240
+ group: ["docs"],
241
+ name: "get",
242
+ summary: "Fetch one SDK doc page or snippet",
243
+ description: "Fetch one feature page (`flags`, `experiments`, \u2026) or nested snippet (`release/experiments`, \u2026), substituting declared {{placeholders}} from caller args.",
244
+ params: [
245
+ { name: "sdk", type: "string", description: "SDK language. Defaults to the `sdk` recorded in the nearest `.shipeasy` when omitted.", required: false, enum: SDK_ENUM },
246
+ { name: "path", type: "string", description: "Page key or snippet 'group/resource'.", required: true, positional: true },
247
+ { name: "framework", type: "string", description: "Framework hint (substitutes {{FRAMEWORK}})." },
248
+ { name: "name", type: "string", description: "Resource name (substitutes {{RESOURCE_NAME}})." }
249
+ ],
250
+ examples: [
251
+ { note: "A feature page", run: "shipeasy docs get --sdk python experiments" },
252
+ { note: "A nested snippet", run: "shipeasy docs get --sdk typescript release/flags --name checkout_v2" }
253
+ ],
254
+ run: async (args) => {
255
+ const sdk = requireSdk(args.sdk);
256
+ const { manifest, fallback } = await loadManifest(sdk);
257
+ const path = resolvePath(manifest, args.path);
258
+ const body = fallback ? DEFAULT_CONTENT[path] : await fetchText(`${pagesBase(sdk)}/${path}`) ?? void 0;
259
+ if (body === void 0) throw new CustomOpError(`Doc '${path}' could not be fetched for '${sdk}'.`, 404);
260
+ return { sdk, path, fallback, content: substitute(body, manifest, args) };
261
+ }
262
+ },
263
+ {
264
+ group: ["docs"],
265
+ name: "skill",
266
+ summary: "Fetch an SDK's installable LLM skill",
267
+ description: "Fetch the SDK's `skill/SKILL.md` (frontmatter intact) so an agent can install it verbatim. The CLI `--install` writes it locally (a consumer fs side-effect).",
268
+ params: [
269
+ { name: "sdk", type: "string", description: "SDK language. Defaults to the `sdk` recorded in the nearest `.shipeasy` when omitted.", required: false, enum: SDK_ENUM },
270
+ { name: "install", type: "boolean", description: "CLI only: write the skill to the local agent skills dir." }
271
+ ],
272
+ examples: [{ run: "shipeasy docs skill --sdk python" }],
273
+ run: async (args) => {
274
+ const sdk = requireSdk(args.sdk);
275
+ const { manifest, fallback } = await loadManifest(sdk);
276
+ const skillPath = manifest.skill ?? "skill/SKILL.md";
277
+ const content = fallback ? DEFAULT_CONTENT[skillPath] : await fetchText(`${pagesBase(sdk)}/${skillPath}`) ?? void 0;
278
+ if (content === void 0) throw new CustomOpError(`No skill published for '${sdk}'.`, 404);
279
+ return { sdk, skillPath, fallback, content };
280
+ }
281
+ }
282
+ ];
283
+
284
+ // src/custom/index.ts
285
+ var customOperations = [grammarOp, ...docsOps];
286
+ var customGroups = [
287
+ {
288
+ group: ["docs"],
289
+ summary: "SDK docs: fetch a language SDK's published docs \u2014 its page tree, feature pages, code snippets, and installable agent skill.",
290
+ description: "SDK docs \u2014 a read-only fetcher over each language SDK's `/docs/` folder, published to plain GitHub Pages (latest only; no backend, no version arg). Point it at an SDK with `--sdk <lang>` (one of: typescript, python, go, java, kotlin, php, swift, ruby) or let it default to the `sdk` recorded in the nearest `.shipeasy`.\n\n**Commands.**\n- `list` \u2014 the SDK's doc tree: feature pages, nested snippet groups, and whether an installable skill exists.\n- `get <path>` \u2014 one feature page (`flags`, `experiments`, \u2026) or nested snippet (`release/flags`), with `{{placeholders}}` substituted from `--name`/`--framework`.\n- `skill` \u2014 the SDK's installable LLM skill (`SKILL.md`); `--install` writes it into your agent's skills dir.\n\nSDKs that haven't adopted the doc standard yet fall back to a built-in default doc set, flagged `fallback: true` in the output."
291
+ }
292
+ ];
293
+ export {
294
+ CustomOpError,
295
+ METRIC_GRAMMAR,
296
+ customGroups,
297
+ customOperations,
298
+ opId
299
+ };
300
+ //# sourceMappingURL=custom.js.map